What is a good way to create a variable in JsRender? - javascript

In a JsRender template, blocks can create variables, so I could write this:
{{if true ~myVariable=myExpensiveFunction()}}
{{:~myVariable}} {{:~myVariable}}
{{/if}}
However, the bogus if is annoying. Is there a better way?

If you can initialize myVariable outside the template, then you can make it a helper variable, and pass it in:
var html = myTmpl.render(data, {myVariable:myExpensiveFunction()});
If you need to initialize in a specific template/data context then as you say, you can use contextual parameters, which are scoped to any template block. Use the tag that wraps that context.
If the context is is top-level in a template, then:
either this is top-level data and you can pass in a helper as above
or it is a 'partial' template rendered from anothor (layout) template, using {{someTag tmpl=.../}}, in which case you can set up your contextual parameter from the calling tag in the other template
or else it is rendering against an array
For that last case you can use {{include}}:
{{include ~myVariable=myExpensiveFunction()}}
{{:~myVariable}} {{:~myVariable}}
{{/include}}
or you can call with noIteration set to true:
var html = myTmpl.render(data, [helpers,] true);
and then wrap in {{for}}:
{{for ~myVariable=myExpensiveFunction()}}
{{:~myVariable}} {{:~myVariable}}
{{/for}}
EDIT:
In your particular case, based on your comments added below, you need to initialize in the context of an item block within a {{for someArray}} - in order to get the item data.
(Actually your item block is a 'partial' template called using {{for someArray tmpl=...}}, but the basic problem is the same).
In this scenario you will indeed need to add an {{include}} wrapper, at top-level (for you) or within the {{for}} if not doing template composition.

Related

Using result of one helper function in another helper function within Handlebars

I am checking if there is anyway that I can use the result of one helper function in another helper function and how can I use it, for example, I am looping through as below
{{#each v.NOVNumber as |vv iindex|}}
And then if I am getting another element as below, using the same index:
{{get v.NOVNoticeTypeName iindex}}
Can I use this element that we have got in a statement like below, to check if that is first or last element etc?
{{#if (isFirst v.NOVNumber vv)}}
You you can use helpers together to create more powerful functions. Ember Composable Helpers provides both a good pattern for using helpers together as well as the specific has-next and has-previous helpers that you need to know if an element is first of last.
An example using has-next
{{#if (has-next page pages)}}
<button>Next</button>
{{/if}}

Dust.js get call count of helper in template

So I have a dust.js helper which requires some jsx module when called and afterwards renders this module as html (some kind of plugin).
{#react type="Text"\}
...
<some Markup>
...
{#react type="Text"\}
{#react type="Text"\}
Meanwhile I have a data structure which contains all the elements that should be rendered on this template (a page)
['1st', '2nd', '3rd']
In my helper I'd like to know how often I called #react. Like incrementing a counter on the context which all helpers called within this template can access.
I was fiddeling around with context.pop() and context.push but wasn't able to mutate the template's context. Every helper gets it's own. So I either need a way to get the call count of the helper or store the current number of invocations of the helper somewhere accessible to the other ones.
However, when doing sth like {#react type="Text" index=0\} and afterwards accessing it with context.get(['page', 'elements', params.index]) it works (of course). But this enforces me to keep count of the elements I am disposing (especially annoying when adding and removing elements)
Hope s/o has an idea, maybe I'm just missing sth really simple.
Cheers.
There is a special global object attached to each Context that contains references you'd like to be available everywhere in your template.
For more information, see Context Globals.
You prepopulate the global by calling dust.context({ foo: 'bar' }) to create a Context object. You can pass this to Dust in your render step instead of a plain Object.
Inside any helper, you can access the global directly to set properties on it:
react: function(chunk, context, bodies, params) {
var numTimesCalled = ++context.global.numTimesCalled;
});
You can use properties in the global in your template. You can think of them as being at the "lowest" level in the context stack.

Meteor: Using while loop in Template

How would I use a while loop in meteor blaze?
I tried using {{unless}} but that did not work. This is what I tried:
<template name="homePage">
<h2>Welcome to home page! </h2>
{{#unless numberOfDays 0}}
<span>hi</span>
{{numberOfDays--}}
{{/#unless}}
</template>
It did not work at all.
There is no #while in spacebars, the templating engine that is default in meteor-blaze.
The #unless keyword is a negated #if, a conditional on something not being truthy. The unless block is not a loop, it can only run once. Like if, the block will either run or not run. The #unless runs if the condition is not truthy.
The only loop construct is #each. You could emulate the behavior of a for or while loop by calculating the results outside the template and placing them in an array variable. In the template, call #each on the array variable.
Although writing a customized handlebars block helper can be used to make custom iteration such as a while loop, Meteor's spacebars is a fork of the handlebars code, and may require a slightly different syntax.
For most simple uses, #each is enough . Reformatting data will often allow #each to be used in a natural way.
From the Spacebar docs
#Each
An #each template tag takes a sequence argument and inserts its content for each item in the sequence, setting the data context to the value of that item:
<ul>
{{#each people}}
<li>{{name}}</li>
{{/each}}
</ul>
The argument is typically a Meteor cursor (the result of collection.find(), for example), but it may also be a plain JavaScript array, null, or undefined.
An "else" section may be provided, which is used (with no new data context) if there are zero items in the sequence at any time.

JSrender: cannot access parent variable inside if condition

as the title says, the problem is clear:
within the construction:
{{if is_completed == 1}}
<div>
<p>{{:#parent.parent.data.myproperty}}</p>
</div>
{{/if}}
the parent properties are not visible!
I solved it by creating construction like:{{for movies ~myproperty=myproperty}} in parent loop, and ~myproperty is visible inside IF conditions, but what if I have several variables, what if I have many-level nesting data structure?
The {{if ...}} block adds another view, so means you need to add a .parent to step up through that view, as in: {{:#parent.parent.parent.data.myproperty}}
You can pass in variables as you said (~myproperty=...) and they will be visible to any depth of nesting.
Your variable can be an object too such as the current data object: ~myObj=#data:
{{sometag a=b ~myObj=#data}}
....
{{:~myObj.myproperty}}
...
{{/sometag}}
so you don't need a separate variable for each property.
You can also access the top-level data object and drill down from there:
{{:~root.foo...myproperty}}.
And finally you can use #get("item") to step up through any number of {{if}} blocks and get the nearest "item" view (i.e. the item view for a repeating {{for ...}} block).
So you would write:
{{:#get("item").data.myproperty}}

handlebars access global variable: if statement

I've got a hbs template where I've got an array of objects and a boolean toggle variable (toggles the template behavior), let's say:
{
objs: list,
mode: true
}
I'm not able to access the mode variable when inside the loop over objs (the context is changed). What I want is to make an if-statement using the upper variable. I found that I can write a custom helper. But is there no other way to access the variable? I also found out, that inside the loop the variable is accessible via {{../mode}} - but still, don't know how to access that.
Finally, I've found a solution:
{{#if ../mode}}xyz{{/if}}

Categories