This is a cool consequence of the new binding syntax. I’ll do my best to explain everything that is going on here.
<can-import from='test/other.stache!' {^@value}='*other' />
{{{*other()}}}
Let’s break this down.
If you haven’t used <can-import>
before, it is a way of importing stuff into a template. You can use it the same way you import stuff into JavaScript files. In this case we are importing a stache template. This is equivalent to doing:
var template = require("test/other.stache!");
template(); // DocumentFragment
The value of test/other.stache!
is a function.
Back to the can-import. This is what we want to look at: {^@value}='*other'
What this does is:
- Set up a one-way binding from child to parent.
- On the child (the can-import’s)
value
property. - Using the at operator
@
to pass the function instead of trying to read a value from the function. - To the parent’s
*other
. -
*
is a special syntax that binds to the References Scope. Think of*other
like a local variable that you can use within the template.
Let’s go point by point. First {^value}
sets up one-way binding. {} means one-way. ^ means from child to parent. Without the ^ it would be parent to child.
On the other side of the attribute, the attribute value, we have *other
. This specifies the parent as being a reference value. Think of a reference like a local variable in JavaScript:
function someFunction(){
var other;
}
In this case other
is a variable that is scoped to someFunction
. In that same way *other
is a variable scoped to the template.
Now the fun part, the @
operator. Normally in stache/mustache functions are called to retrieve their value. That’s why if you have a method on a viewModel you can do {{method}}
. A side-effect of this is that this means that if you want to pass the function itself there was never really a way to do that before. Can 2.3 introduces Call expressions which are the way forward. With call expressions you call the function like {{foo()}}
. In 3.0 Call expressions might be the only way to use functions, but for now we have to deal with backwards compatibility and that means the at operator is needed so that we can hold on to the function itself to use later.
The cool part is that this means you can do things like pass a function on one component to another component.
Ok, let’s continue. can-import
is a custom element just like any other custom element. This means it has a viewModel. can-import’s viewModel is a Promise, which is async. So this is why we bind to the import’s value
property, the value will be set after the Promise has resolved.
Lastly, now that we have *other
as a reference value we can use it; it’s a function. To call a function as a call expression you use the ()
syntax like in JavaScript.
{{{*other()}}}
Will call the *other
function (a stache renderer) which returns a DocumentFragment. The triple curly brace syntax is needed so that the unescaped value is is inserted.
And that’s it! I hope you can see that by solving a long-standing problem in CanJS, the ability to pass functions in templates, we’ve accidentally created a new way to use partials, without any sort of special syntax just for them.