How to convert handlebars partial parameters to pug/jade? - handlebars.js

Small but difficult question for me. How to convert this code to pug? I'm currently learning web programming and writing my first project in pug.
{{#each people}}
{{> myPartial prefix=../prefix firstname=firstname lastname=lastname}}.
{{/each}}

Pug doesn't have partials, but it does have mixins, which are a similar concept that allow you to reuse and pass parameters to blocks of code.
Assuming you've rewritten myPartial as a valid mixin called myMixin, and assuming people is an array of objects with properties firstname and lastname, you could write this in Pug as:
each person in people
+myMixin(person.firstname, person.lastname)

Related

How to render partials/helpers *inside* a string variable?

Say I've got the following template/scenario:
{{partial-container container}}
{{{content.html}}}
{{#each content.partials}}
{{this}} // <-- here I'd like to render partials that users requested.
{{/each}}
Goals
[Done] I want to render a block of text, html-escaped, using the html property.
From the JSON, we also get a list of "partials" to render, but I can't figure out how to make this work.
Ideally, the syntax would be something like this:
{{partial-container container}}
{{{content.html}}}
{{#each content.partials}}
{{ > {{this}} }}
{{/each}}
But that throws a syntax error. Is there any way to interpret the contents of a variable as the name for a partial to render (and do so)?
I am assuming that your "list of partials" is an array of names matching with registered partials. Something like:
"partials": ["fooPartial", "barPartial", "fooPartial"]
The Handlebars documentation states that partials can be dynamically selected using a subexpression, but this subexpression must be a function that returns the partial name. This means that something as simple as {{> (this)}} will not work because our this is the string value of our partial name and not a function.
I see two ways of achieving our goal.
Option 1: Map the partial names to functions
If we have the ability to modify the data we are sending to our template, we could map the partial names into functions that return the name:
"partials": ["fooPartial", "barPartial", "fooPartial"].map(partialName => () => partialName)
These functions would allow us to dynamically insert our partials into our template with {{> (this)}}.
See this fiddle for an example.
Option 2: Use the lookup helper
If modifying our input data is not an option, we can use the Handlebars built-in lookup helper. The trick here is that, within our #each loop, we must step-up a context-level to get our partials array and then use the #index helper variable to get the partial name at the current index. The template would become:
{{#each content.partials}}
{{> (lookup ../content.partials #index)}}
{{/each}}
See this fiddle for an example.

The meaning of "scope" in Handlebars

I am confused by "scope" in the Handlebars template engine. In its documentation on block helpers, I read
"Private variables provided via the data option are available in all
descendent scopes. Private variables defined in parent scopes may be
accessed via pathed queries."
I understand the meaning of scope as used in programming languages (where {} are often used to create scopes). But what does "scope" refer to in Handlebars templating?
It is actually quite similar, see an example here: https://jsfiddle.net/veraee/63gs19j3/11/
Just to make it clear, there are two types of "variables" in handlebars:
The model/context. This is the data you inject into the template on redering. Use this for your normal work.
These variables are referenced in the template via its name in {{}}:
{{firstname}}
and are exposed in the javascript of the helpers via "this":
this.firstname
The "#"-variables. This data is generated inside the helpers via javascript.
These variables are referenced in the template via its name with '#'-prefix:
{{#foo}}
and are exposed in the javascript of the helpers via "options.data":
options.data.foo
The citation from the handlebars doc in the OP is about number 2.
In a programming language the "{" enters a scope,
in handlebars a block "{{#myBlock..." enters a scope.
Similar to the programming language you can use all variables from the outer scope in the inner scope (foo, bla),
but if you redefine one in the inner scope (bla), the original value will
be shadowed in the inner scope. When leaving the inner scope and being again
in the outer scope, you get the old value of bla again.
But note these differences to programming languages:
This scoping does not happen by some magic of the programming language syntax,
you have to do in on your own, as the doc also mentions, i.e. this way:
data = Handlebars.createFrame(options.data);
As a bonus, you can reach the shadowed variables (which is usually not possible in programming languages)
by prefixing the name with "../" which means: look at the previous (aka. outer) scope (see the "{{#../bla}}" in the inner scope in the example).

assemble: Access global variables in {{parseJSON}}

Let's say you have a partial of some sort, which uses a global variable:
<img src="{{assets}}/logo.png">
Once you include the partial with specific data, either {{parseJSON}} or external JSON data:
{{#parseJSON '{"demo": true}'}}
{{>navigation}}
{{/parseJSON}}
all global variables like {{assets}} "killed" or at least overridden. Is there any chance to have still access?
Thanks in advance!
this is a known "issue" with Handlebar's partials in that the context inside a partial only includes the passed in context and no parent context, etc.. you can read more about the issue here.
fortunately the Assemble team provides a {{partial}} helper that will allow access to a more "expected" context, including global properties. once this helper is installed, you use it in a slightly different way than a normal partial:
{{#parseJSON '{"demo": true}'}}
{{partial "navigation"}}
{{/parseJSON}}
note that the partial helper is invoked with the name of the partial to include as a string.
that all being said, a new version of Handlebars was just released (v2.0.0-alpha.1) that may provide support for this natively. check out the more recent posts of issue thread i linked to above.
hope this helps.
As a workaround, the other way to cope with this is to pass the parent context explicitly to the partial:
{{#..}}
{{>partial}}
{{/..}}
Yeah.

Adding Handlebars helpers to scaffolt

How does one go about adding Handlebars helpers to the scaffolt processing that comes with brunch? I'd like to do some more interesting conditional statements in my scaffolt templates but need to understand this process.
Oh, also, does anyone have any smart helpers that look at a name and deduce if the name indicates being singular or plural?

Path of Twig with variable of Backbone

I would like to know how was it possible to insert code from Backbone / Underscore function in twig?
Here is my problem:
{{path('getArticle', {"id": <%= id %>})}}
I need to change this variable : <%= id %>
This does not work because Twig Parse before the Backbone code. So I do not know how to give a variable of this type?
Thank you in advance
I suppose you are using Symfony in the server side, along with TWIG.
In that case, you just have to send the $id variable to your TWIG template
public function callMyTwigAction($deskId)
{
$id=whatIwant();
return array('id' => $id);
}
and then just call in your TWIG file :
{{path('getArticle', {"id": id})}}
It looks like you are mismatching client template and server template.
A client template like Underscore Template (or rather use Mustache) is transforming raw web services data (JSON or XML) into HTML and is (probably) written in Javascript.
Server side template usually transforms business objects (Java/PHP classes) into HTML and uses an engine such as TWIG or Velocity.
With the more complicated architecture I would propose three things :
simplify your architecture :) Something is perhaps wrong.
Make a web service to get the path of a given id (but this would make the architecture even more complex)
create an array of paths with Twig in your javascript. Thiw may be ok if there is less than 200 articles and if this page is not too often displayed.
Do you use TWIG in the server side ? What technology stack do you use ?
Use FOSJSRoutingBundle. It generates a map of all your exposed TWIG routes, which you can then use in your Javascript.
Making the Routing component global, or inject it into your underscore template. Then simply call it similarly to how you would do it in TWIG, but with a JS notation:
Get Article <%= id %>

Resources