socketstream/socketstream

View on GitHub
docs/partials/tutorials/client_side_templates.html

Summary

Maintainability
Test Coverage
<a href="https://github.com/socketstream/socketstream/edit/master/src/docs/tutorials/en/client_side_templates.ngdoc" class="improve-docs"><i class="icon-edit"> </i>Improve this doc</a><h1><code ng:non-bindable=""></code>
<div><span class="hint"></span>
</div>
</h1>
<div><div class="client-side-templates-page"><h2 id="client-side-templates">Client-Side Templates</h2>
<p>Client-side templates generate HTML in the browser, allowing SocketStream to send raw, layoutless data over the websocket. This not only dramatically reduces bandwidth, but also gives you flexibility to render the data into HTML in any number of ways.</p>
<h4 id="client-side-templates_why-use-client-side-templates">Why use client-side templates?</h4>
<p>If your app is really simple, you might be happy manually building your HTML using jQuery functions:</p>
<pre class="prettyprint linenums">
// client/code/main/index.js
var people = [
  { name: 'Alice', major: 'Astronomy'},
  { name: 'Bob', major: 'Biology' }
];

$(document).ready(function() {
  var i;

  for (i = 0; i &lt; people.length; i++) {
    $('#people').append("&lt;li&gt;" + people[i].name + " the student studies &lt;strong&gt;" +
      people[i].major + "&lt;/strong&gt;&lt;/li&gt;"
    );
  }
});
</pre>
<p>However, not only does this solution scale poorly for larger templates, but mixing together display logic and HTML is bad practice. Enter client-side templates.</p>
<h4 id="client-side-templates_template-engines">Template Engines</h4>
<p>SocketStream supports two types of client-side template engines out-of-the-box:</p>
<h6 id="client-side-templates_template-engines_ember">ember</h6>
<p>Outputs inline templates in the correct format for Ember.js.</p>
<h6 id="client-side-templates_template-engines_angular">angular</h6>
<p>Outputs inline templates in the correct format for Angular.js.</p>
<h6 id="client-side-templates_template-engines_default">default</h6>
<p>Simply wraps each template in a DIV tag with an ID prefix of &#39;tmpl-&#39;. Suitable for use with many template engines, including jQuery Templates (as used by SocketStream 0.2).</p>
<p>To use a built-in template engine, pass the name as a string:</p>
<pre class="prettyprint linenums">
ss.client.templateEngine.use('ember');
</pre>
<p>As built-in template engines are only simple wrappers, most of the time you&#39;ll want to use one of the several template languages supported via optional modules on npm:</p>
<ul>
<li><a href="https://github.com/socketstream/ss-hogan">ss-hogan</a> Mustache templates (compiled on the server, requires small client-side lib). This is our recommended template engine.</li>
<li><a href="https://github.com/socketstream/ss-coffeekup">ss-coffeekup</a> CoffeeKup templates (compiled on the server, no client-side code required)</li>
<li><a href="https://github.com/sveisvei/ss-clientjade">ss-clientjade</a> Client-side Jade templates (compiled on the server, requires small client-side lib)</li>
</ul>
<p>To use an external optional template engine, pass the module as so:</p>
<pre class="prettyprint linenums">
ss.client.templateEngine.use(require('ss-hogan'));
</pre>
<p>If you can&#39;t find a module for your favorite templating library it&#39;s easy to <a href="https://github.com/socketstream/socketstream/blob/master/doc/guide/en/template_engine_wrappers.md">create your own</a>.</p>
<h4 id="client-side-templates_mix-and-match-different-template-engines">Mix and match different template engines</h4>
<p>All client-side templates live in the <code>client/templates</code> folder; however you don&#39;t have to serve every template with the same engine.</p>
<p>SocketStream allows you to mix and match different templates, perfect for trying out something like Ember.js without having to convert all your exiting templates over at once.</p>
<p>You may limit the scope of a template engine by passing the name of a directory as the second argument.</p>
<pre class="prettyprint linenums">
// serve all templates with ss-hogan
ss.client.templateEngine.use(require('ss-hogan'));
// apart from any in the /client/ember directory
ss.client.templateEngine.use('ember', './ember');
</pre>
<p>The new style of SocketStream is to use relative paths from the client directory. The default destinations for templates still work as shown below.
However it is a good habit to specify the directory with the new notation style. If you want to have
templates outside the client, you can access the project directory with the <code>../</code> prefix.</p>
<pre class="prettyprint linenums">
// serve all templates with ss-hogan
ss.client.templateEngine.use(require('ss-hogan'));
// apart from any in the /client/templates/em directory
ss.client.templateEngine.use('ember', '/em');
</pre>
<h4 id="client-side-templates_example">Example</h4>
<p>Here we&#39;re using the <a href="http://twitter.github.com/hogan.js/">Hogan</a> templating library, using the <code>ss-hogan</code> module bundled by default when you create a new project.</p>
<p>In this folder, let&#39;s create a file called <code>person.html</code>:</p>
<pre class="prettyprint linenums">
&lt;!-- client/templates/person.html --&gt;
&lt;li&gt;{{ name }} the student studies &lt;strong&gt;{{ major }}&lt;/strong&gt;&lt;/li&gt;
</pre>
<p><strong>NOTE:</strong> If you prefer, you may use a formatter to construct your HTML templates. For example, to use Jade, use <code>.jade</code> instead of <code>.html</code> for your template&#39;s file extension.</p>
<p>If you refresh the page and view the HTML source code you&#39;ll see a new <code>&lt;script&gt;</code> tag containing the compiled template.</p>
<p>The <code>person.html</code> file in the <code>templates</code> folder is now accessible via <code>ss.tmpl[&#39;person&#39;]</code>. If the file was in a subdirectory <code>model/person.html</code>, then it would be accessible via <code>ss.tmpl[&#39;model-person&#39;]</code>.</p>
<p>Now that we have a template, let&#39;s put it to good use by refactoring our code:</p>
<pre class="prettyprint linenums">
// in your client-side code
var people = [
  { name: 'Alice', major: 'Astronomy'},
  { name: 'Bob', major: 'Biology' }
];

$(document).ready(function() {
  var i;

  for (i = 0; i &lt; people.length; i++) {
    $('#people').append(ss.tmpl['person'].render(people[i]));
  }
});
</pre>
<h4 id="client-side-templates_serving-different-templates-to-different-clients">Serving different templates to different clients</h4>
<p>By default all templates will be sent to all single-page clients you define with:</p>
<pre class="prettyprint linenums">
ss.client.define()
</pre>
<p>However, by organizing your templates into directories, you can specify which templates will be sent to each client as so:</p>
<pre class="prettyprint linenums">
// app.js
ss.client.define('iphone', {
  view: 'app.jade',
  css:  ['libs', 'app.styl'],
  code: ['libs', 'app'],
  tmpl: ['main', 'mobile']  // will only send templates in the 'main' and 'mobile' directories
});
</pre>
</div></div>