Live-binding Handlebars/Mustache–like templates.
Read the can-stache API docs on CanJS.com.
See the latest releases on GitHub.
The contribution guide has information on getting help, reporting bugs, developing locally, and more.
Live binding handlebars templates
Home Page: https://canjs.com/doc/can-stache.html
License: MIT License
Live-binding Handlebars/Mustache–like templates.
Read the can-stache API docs on CanJS.com.
See the latest releases on GitHub.
The contribution guide has information on getting help, reporting bugs, developing locally, and more.
Test "no memory leaks with #each (#545)" fails randomly.
https://github.com/canjs/can-stache/blob/master/test/stache-test.js#L2901
If you run tests again, it should pass the tests... I suspect it has something to do with setTimeout
. Maybe the second setTimeout
should be called from inside of the first setTimeout
, because browsers doesn't guarantee the execution order of callbacks set with setTimeout
? Proof:
From: canjs/canjs#1157
Support dynamic property access with a []
operator.
This can be done by making an expression Type similar to Call: https://github.com/canjs/can-stache/blob/master/src/expression.js#L117
And then making sure it's parsed and created correctly around here: https://github.com/canjs/can-stache/blob/master/src/expression.js#L625
Test case in b91adc4
var exprData = expression.parse('each ~foo');
This throws with:
TypeError: Cannot read property '0' of undefined
at Object.hydrateAst (http://localhost/can-stache/src/expression.js:659:47)
at Object.hydrateAst (http://localhost/can-stache/src/expression.js:688:23)
at Object.parse (http://localhost/can-stache/src/expression.js:647:19)
at Object.<anonymous> (http://localhost/can-stache/test/expression-test.js:690:28)
From: canjs/canjs#2329
%first
and %last
that would be true
or false
if the index was right.
This could probably be done like:
{{#each items}}
{{#eq @index items.length}}last{{/eq}}
{{/each}}
If you have a template like:
<h1>{{place['place:name']}}</h1>
And place
is undefined, an error options.get is not a function
is thrown in helpers/core.js.
With non-bracket syntax this sort of thing is fine:
<h1>{{place.placeName}}</h1>
This is the same error I got when using colons in stache before switching to brackets ({{place.place:name}}
.
When passing a bracket expression as a two-way bound value like:
<my-clicker {(val)}="thing['other:thing']" />
Modifications to val
in the my-clicker
VM do not propagate to the original value.
If you change thing['other:thing']
to thing.otherThing
the two-way binding works.
These throw errors at the moment:
{{device[prop].anotherProp}}
{{device[prop][anotherProp]}}
From: canjs/canjs#2318 Fix this in 3.0, then see if we can back-port to 2.3.
Given a template like this:
{{#each objects}}
{{.}}
{{/each}}
If you overwrite a key that is already being displayed (e.g., foo
), the view does not update.
vm.attr('objects.foo', 'blah');
Broken in 3.0: http://jsbin.com/buhosip/edit?html,js,output
The isIterable
case within the each helper is not being hit by any of the current tests. That scenario would cause isIterable
to be true within this helper?
@justinbmeyer brought this while working on #62. We expected a can.Map to match this case.
From: canjs/canjs#1360
{{#with somethingElse}}
{{#each blargh}} {{! Assume blargh objects have a .setActive method }}
{{%self.name}} {{%self.setActive}} {{setActive}}
{{/each}}
{{/with}}
we have to document this new {{each}}
helper #20
If you use a bracket in a helper, the entire expression is turned into a bracket expression and does not work properly.
For example, using a helper like:
<p>{{myHelper ['name']}}</p>
Will create and AST of:
{
"type":"Bracket",
"root":{
"type":"Lookup",
"key":"myHelper"
},
"children":[
{
"type":"Literal",
"value":"name"
}
]
}
Which is the exact same AST that will be created if you had a template like:
<p>{{myHelper['name']}}</p>
The tokenizer strips out spaces so there's no way to differentiate between these two templates.
If that's the case, we should document this and suggest people use the call expression version of a helper if they are using brackets.
i.e <p>{{myHelper(['name'])}}</p>
This trailing / will not work in non-steal environments.
Internet Explorer 11 can not cope with DOM mutations to tables which do not have <tbody>
elements and which are (directly or indirectly with subtree:true
) being observed by a MutationObserver
.
They cause a hard crash of the entire browser with a fault code similar to Unhandled exception at 0x05D424C1 (mshtml.dll) in iexplore.exe: 0xC0000005: Access violation reading location 0x00000008.
Stache should probably take care to ensure that <tbody>
elements are always present, or should not use MutationObserver
for IE 11. However, given that any other code operating on a page might still be registering mutation observers, the first (ensuring that <tbody>
is always present) is probably a better idea.
Likewise, IE 11 has additional problems with crashes when using insertAdjacentHTML
on a <tbody>
element, which should probably be guarded against as well.
See e.g. meteor/meteor#6081 for Meteor, which ran into problems with this curiosity as well.
The docs for can-stache.registerPartial
show stache.registerHelper("item.stache", "<li>{{name}}</li>");
.
in https://github.com/canjs/can-stache/tree/master/docs/tags there is no partials.md
in the folder above, it is located.
in the readme partials key
is not documented
on the new canjs website (http://canjs.github.io/canjs/doc/can-stache.helpers.partial.html) the url contain helpers
?
@matthewp something wrong there?
They’re pretty bare-bones right now: https://v3.canjs.com/doc/can-stache/helpers/route.html
route helpers are not being registered as helpers because the file isn't required in the main js file.
From: canjs/canjs#1735
{{#each readings}}
<some-component reading="{.}"/>
{{/each}}
Some times I want to wrap it with <another-component>
and I have to change {.}
to {../.}
or even '{../../.}' for double wrap
{{#each readings}}
<another-component/>
<and-another-component/>
<some-component reading="{../../.}"/>
</and-another-component/>
</another-component/>
{{/each}}
If one could have name for each
heper context and refere to it by given name, it would be more convinient without need of backtrack paths.
{{#each readings "reading"}}
<another-component/>
<and-another-component/>
<some-component reading="{reading}"/>
</and-another-component/>
</another-component/>
{{/each}}
emberjs does it using sintax something like like: {{#each readings as "reading"}}
Related:
can.stache.registerConverter("numberToString",{
get: function(source){
return source() + "";
},
set: function(newVal, source){
source(newVal === "" ? null : +newVal);
}
});
<input {($value)}="numberToString(~age)">
From: canjs/canjs#2200
We need a way to provide a local scope within a section. This will enable components within an each
to pass data to each other:
{{#each items}}
<date-picker {^*date}="*placeholder"/>
<date-slider {^*date}="*placeholder"/>
<date-saver {current}="./date" {suggested}="*placeholder"/>
{{/each}}
No more converting things to computes, you always get the actual value, use ~ if you want a compute.
From private conversations, should converters have a special naming convention? For example:
These are converter helpers. They have both a getter which is used to set the element's value
and a setter which is used to set the scope value in some way.
converter helpers are cool.
However, should they look differently from normal helpers (which are camelCase) to convey the fact that they are two-way rather than one-way like normal helpers? Does using kebab case aid in distinguishing them or hinder understanding?
From:
.
is not live-bindable so things like view bindings aren't updated correctly.
I think the solution is to make sure that most contexts are actually saved as a compute.
in can 3.0 we should remove the deprecated @Index and @key from helper
https://github.com/canjs/can-stache/blob/master/helpers/core.js#L63
Duplicate of canjs/canjs#2361
From: canjs/canjs#1476
A template like:
// Ex. 1
<p class="{{ foo[bar] }}"></p>
// Ex. 2
<p class="{{ foo['bar:baz'] }}"></p>
Will throw an error: Uncaught TypeError: attr.substr is not a function
here
I've tracked this down to helperAndValue which is attempting to find the key it should use to lookup the value in the scope.
In Ex. 1
the methodExpr
is an instance of Lookup
so the methodKey
should be methodExpr.key.key
In Ex. 2
the methodExpr
is an instance of Literal
so the methodKey
should be methodExpr.methodKey.key._value
Even with these changes in place, it doesn't look like the resolution of their values works inside attributes.
From: canjs/canjs#1331
Solution provided in the above issue:
nope. But to add it to stache, you need to get makeLiveBindingPartialRenderer (https://github.com/bitovi/canjs/blob/minor/view/stache/mustache_core.js#L441) called with expressionData similar to how makeLiveBindingBranchRenderer is (https://github.com/bitovi/canjs/blob/minor/view/stache/mustache_core.js#L531). I'm not sure why it isn't but I bet the fix is easy.
Then, you'll need (https://github.com/bitovi/canjs/blob/minor/view/stache/mustache_core.js#L456) to be passed something like scope.add(newContext)
.
To look up newContext, you can use
var exprData = core.expressionData(expression),
And b/c minor's exprData is much easier to use ... you should be able to something like:
exprData._args[0].value(scope, options)
Ping me on gitter if you want to help make this happen.
Example: http://jsfiddle.net/02aq58nh/23/
From: canjs/canjs#1263
Fix is to change:
each(el.childNodes, function (option) {
if (option.value) {
option.selected = !! isSelected[option.value];
}
});
To use:
if (typeof option.value != 'undefined') {
option.selected = !! isSelected[option.value];
}
Because there is no constructor.keys
.
This completes what's needed for #37
From: canjs/canjs#2284
If not yet supported, please support whitespace control like Handlebars: http://handlebarsjs.com/expressions.html#whitespace-control
My use case: :empty
pseudo selector, which does not match
<div> </div>
<div>
<!-- test -->
</div>
<div>
</div>
Background:
<script type="text/stache" id="template">
<span>{{name}}</span>
</script>
<script type="text/steal-module">
var stache = require("can-stache");
var render = stache.querySelector("#template");
</script>
Not sure on the name, here's some options:
Code for this function is essentially just:
function qs(selector) {
var script = DOCUMENT().querySelector(selector);
var txt = script.innerHTML;
return stache(txt);
}
From canjs/canjs#2438
Related: canjs/canjs#2384
http://justinbmeyer.jsbin.com/tinece/2/edit?html,js,output
Related:
From canjs/can-stache-bindings#9.
<input type="text" id="test" ($foobar)="doStuff(%event, ...%args)">
I believe this is a general purpose JavaScript expression parser. It would be nice if other templating languages could use it (without depending on can-stache). can-js-expression
maybe?
since custom context for stache partials is added, it should be documented
#22
This is the warning on the console.
WARN: can/view/stache/mustache_core.js: Unable to find helper "(right hand side of colon)".
Here is a fiddle showing the problem:
https://jsfiddle.net/8hv2k1cp/4/
Related: #35
I think we need:
<input type='checkbox' {($checked)}=inList(item, list)/>
<select {($value)}="toString(~someValue)">
- converts null
, undefined
, 5
, false
and as much as possible to a string representation and vice versa.If you use the bracket syntax in a call expression, the entire statement is turned into a bracket expression and does not work properly.
For example, using an expression like:
<p>{{myHelper(['name'], 'F')}}</p>
Will create and AST of:
{
"type":"Bracket",
"children":[
{
"type":"Literal",
"value":"name"
}
]
};
This should (probably) be a call expression with two children like this:
{
"type":"Call",
"method":{
"type":"Lookup",
"key":"@myHelper"
},
"children":[
{
"type":"Bracket",
"children":[
{
"type":"Literal",
"value":"name"
}
]
},
{
"type":"Literal",
"value":"F"
}
]
}
Example with latest: http://jsbin.com/tinece/4/edit?html,css,js,output
<th class="{{#if sorting}}sort-{{#if ascending}}ascend{{else}}descend{{/if}}{{/if}}">
From: canjs/canjs#1241
For canjs/canjs#2647, we will be running a build before running tests. The joinBase
test fails in production mode because the expected URL is not in /dest
.
From:
can-tag
This is partially an issue for: https://github.com/canjs/can-view-callbacks, but most of the implementation would need to exist in can-stache. I think the api should be something like:
var MyComp = Component.extend({
tag: "my-comp"
});
viewCallbacks.attr("my-comp", function(el, attrData){
return new MyComp(el, attrData);
}, true);
With the basics done, can-tag
could be pretty easily implemented.
viewCallbacks.attr("my-comp", function(el, attrData){
return new viewCallbacks.tag[attrData.attributeName](el, attrData);
}, true);
Proposal for simple inline named partials which would enable simple, fast, recursive templates.
The syntax and a simple recursive example:
Template:
{{<partialName}}
<li>
{{.name}}
<ul>
{{#each .children}}
{{>partialName .}}
{{/each}}
</ul>
</li>
{{/partialName}}
<ul>
{{>partialName initialScope}}
<li>( {{message}} )</li>
</ul>
viewModel:
viewModel: {
initialScope: {
name: "Turtles",
children: [
{
name: "Turtles",
children: []
},
{
name: "Turtles",
children: []
},
{
name: "Turtles",
children: [
{
name: "Turtles",
children: [
{
name: "Turtles",
children: [
{
name: "Turtles",
children: []
}
]
},
{
name: "Turtles",
children: []
},
{
name: "Turtles",
children: []
}
]
},
{
name: "Turtles",
children: []
}
]
}
]
},
message: "All the way down"
}
Output:
Named partials are also useful for logically separating complex templates - something .jsx does very well. Templates become much cleaner and easier to read when logically separated.
Useful for readability even without recursion:
{{<renderThumbnail}}
<li class="{{#is . selectedImage}}selected{{/is}}"
($click)="updateSelectedImage( . )"
($mouseenter)="showPreview( . )"
($mouseleave)="hidePreview()"
>
<img {$src}=".thumbSrc" {$alt}=".title">
</li>
{{/renderThumbnail}}
{{<renderIndicators}}
<ul class="image-indicator-dots">
{{#each .}}
<li class="{{#is . selectedImage}}active-indicator{{/is}}"
($click)="updateSelectedImage( . )"
></li>
{{/each}}
</ul>
{{/renderIndicators}}
<div class="article-images">
<ul class="vertical-thumbnail-selector">
{{#allImages}} {{>renderThumbnail .}} {{/allImages}}
</ul>
<div class="main-image-wrapper">
<img {$src}="selectedImage.fullSrc" {$alt}="selectedImage.title">
<span class="main-image-title">{{selectedImage.title}}</span>
</div>
{{>renderIndicators allImages}}
</div>
That's maybe overkill for a small bit of markup but it demonstrates the idea for larger ones.
How do you feel about this?
using steal-tools to build a app with stache templates will produce an output like this
define('[email protected]#button-comp/[email protected]#steal-stache', [
'module',
'can-stache',
'can-stache/src/mustache_core',
'[email protected]#can-view-import',
'[email protected]#can-stache-bindings'
], function (module, stache, mustacheCore) {
var renderer = stache([
{
'tokenType': 'start',
'args': [
'span',
false
]
},
{
'tokenType': 'attrStart',
'args': ['($click)']
},
{
'tokenType': 'attrValue',
'args': ['click()']
},
{
'tokenType': 'attrEnd',
'args': ['($click)']
},
{
'tokenType': 'end',
'args': [
'span',
false
]
},
{
'tokenType': 'special',
'args': ['name']
},
{
'tokenType': 'close',
'args': ['span']
},
{
'tokenType': 'done',
'args': []
}
]);
return function (scope, options, nodeList) {
var moduleOptions = { module: module };
if (!(options instanceof mustacheCore.Options)) {
options = new mustacheCore.Options(options || {});
}
return renderer(scope, options.add(moduleOptions), nodeList);
};
});
btw, this is a very short stache template!
<span ($click)="click()">{{name}}</span>
the issue
i see anytime tokenType
and attrStart
and attrValue
and args
it's about minification of code. for example: if we use tT
instead of tokenType
we will reduce 6 byte. the minification tool in steal-tools cant minfiy that code!
if we have a big template, we can save a lot of traffic
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.