UNPKG

can

Version:

MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.

215 lines (151 loc) 6.36 kB
@function can.stache @parent canjs @release 2.1 @group can.stache.pages 0 Pages @group can.stache.static 1 Methods @group can.stache.types 2 Types @group can.stache.tags 3 Basic Tags @group can.stache.htags 4 Helper Tags @group can.stache.plugins 5 Plugins @link ../docco/view/stache/mustache_core.html docco @test can/view/stache/test/test.html @plugin can/view/stache @download http://canjs.us/release/latest/can.stache.js @description Live binding Mustache and Handlebars-comptable templates. @signature `can.stache(template)` Processes the template and returns a [can.view.renderer] function that renders the template with data and local helpers. @param {String} template The text of a mustache template. @return {can.view.renderer} A renderer function that returns a live document fragment that can be inserted in the page. @body ## Use Stache templates are a [mustache](https://mustache.github.io/mustache.5.html) and [handlebars](http://handlebarsjs.com/) compatable syntax. They are used to: - Convert data into HTML. - Update the HTML when observable data changes. - Provide custom elements and bindings. The following creates a stache template, renders it with data, and inserts the result into the page: ``` // renderer is a "renderer function" var renderer = can.stache("<h1>Hello {{subject}}</h1>"); // "renderer functions" render a template and return a // document fragment. var fragment = renderer({subject: "World"}) // A document fragment is a collection of elements that can be // used with jQuery or with normal DOM methods. fragment //-> <h1>Hello World</h1> document.body.appendChild(fragment) ``` Render a template with observable data like [can.Map]s or [can.List]s and the HTML will update when the observable data changes. ``` var renderer = can.stache("<h1>Hello {{subject}}</h1>"); var map = new can.Map({subject: "World"}); var fragment = renderer(map) document.body.appendChild(fragment) map.attr("subject","Earth"); document.body.innerHTML //-> <h1>Hello Earth</h1> ``` There's a whole lot of behavior that `can.stache` provides. The following walks through the most important stuff: - [can.stache.magicTagTypes] - The different tag types like `{{key}}` and `{{#key}}...{{/key}}` - [can.stache.scopeAndContext] - How key values are looked up. - [can.stache.expressions] - Supported expression types like `{{helper arg}}` and `{{method(arg)}}` - [can.stache.Acquisition] - How to load templates into your application. - [can.stache.Helpers] - The built in helpers and how to create your own. - [can.stache.Binding] - How live binding works. ## Differences from can.mustache `can.stache` is largely compatable with [can.mustache]. There are three main differences: - Passes values in the scope to [can.Component] with `{key}`. - [can.stache.sectionRenderer section renderers] return documentFragments. - [can.mustache.helpers.elementCallback Element callbacks] like `{{(el) -> CODE}}` are no longer supported. ### Passing values in the scope to can.Components A [can.mustache] template passes values from the scope to a [can.Component] by specifying the key of the value in the attribute directly. For example: can.Component.extend({ tag: "my-tag", template: "<h1>{{greeting}}</h1>" }); var template = can.mustache("<my-tag greeting='message'></my-tag>"); var frag = template({ message: "Hi" }); frag //-> <my-tag greeting='message'><h1>Hi</h1></my-tag> With stache, you wrap the key with `{}`. For example: can.Component.extend({ tag: "my-tag", template: "<h1>{{greeting}}</h1>" }); var template = can.stache("<my-tag greeting='{message}'></my-tag>"); var frag = template({ message: "Hi" }); frag //-> <my-tag greeting='{message}'><h1>Hi</h1></my-tag> If the key was not wrapped, the template would render: frag //-> <my-tag greeting='message'><h1>message</h1></my-tag> Because the attribute value would be passed as the value of `greeting`. ### Section renderers return documentFragments A [can.mustache.sectionRenderer Mustache section renderer] called like `options.fn()` or `options.inverse()` would always return a String. For example, the following would wrap the `.fn` section in an `<h1>` tag: can.mustache.registerHelper("wrapH1", function(options.fn()){ return "<h1>"+options.fn()+"</h1>"; }); var template = can.mustache("{{#wrapH1}}Hi There!{{/#wrapH1}}"); template() //-> <h1>Hi There</h1> `can.stache`'s [can.stache.sectionRenderer section renderers] return documentFragments when sections are not contained within an html element. This means the result of the previous helper would be: <h1>[object DocumentFragment]</h1> Instead, helper functions should manipulate the document fragment into the desired response. With jQuery, this can be done like: can.stache.registerHelper("wrapH1", function(options.fn()){ return $("<h1>").append( options.fn() ); }); var template = can.stache("{{#wrapH1}}Hi There!{{/#wrapH1}}"); template() //-> <h1>Hi There</h1> ### Element callbacks are no longer supported `can.mustache` supported [can.mustache.helpers.elementCallback element callbacks] like `{{(el) -> CODE}}`. These are not supported in `can.stache`. Instead, create a helper that returns a function or register a [can.view.attr custom attribute]. can.stache.registerHelper("elementCallback", function(){ return function(el){ CODE } }); can.view.tag("element-callback", function(el){ CODE }) ## Working with Promises Promises passed into a template have the following attributes that are observable: - isPending - isResolved - isRejected - value - the resolved value of the promise, only available if `isResolved` is true - reason - the rejected value, only available if `isRejected` is true - state - "pending", "resolved", or "rejected" Stache Template ``` <script id="template" type="text/stache"> {{#if items.isPending}} <img src="loading.png"/> {{/if}} {{#if items.isResolved}} {{#each items.value}} <h2>{{name}}</h2> {{/each}} {{/if}} {{#if items.isRejected}} <img src="error.png"/> {{/if}} </script> ``` JavaScript ``` var promise = $.get('/items'); var template = can.view('template', { items: promise }); ``` ## Tags @api can.stache.tags