I need a handlebars version of my for loop. So I registered a helper to make an incremental, classic for loop structure. My problem is I can't use variables inside that handlebars front-end notation. Everything works fine with my ifCond
registered helper, but my for loop is not working. iterator
, page
and endingLink
are variables which are rendering from a controller.js file. I mean, these variables are viable outside of the for
loop, but I can't use their values inside the loop. For example:
<a href="/?page={{iterator}}">{{iterator}}</a>
href or innerHTML value of the tag equals to nothing. Any ideas?
This is my code :
hbs.registerHelper('for', function(from, to, incr, block) {
let accum = '';
for(var i = from; i <= to; i = incr)
accum = block.fn(i);
return accum;
});
Front-end implementation
{{#ifCond page '>' 1 }}<a href="/?page={{page}}">Before</a>{{/ifCond}}
{{#for iterator endingLink iteratorInc}}
{{#ifCond iterator '===' page}}
<a href="/?page={{iterator}}">{{iterator}}</a>
{{/ifCond}}
<a href="/?page={{iterator}}">{{iterator}}</a>
{{/for}}
{{#ifCond page '<' numberOfPages }}<a href="/?page={{page}}">After</a>{{/ifCond}}
CodePudding user response:
To explain the problem, I will start with a simplified version of your template:
{{#for iterator endingLink iteratorInc}}
{{log iterator}}
{{/for}}
In this simplified template, we are using your for
block helper. The body of the block is simply {{log iterator}}
which will use the Handlebars built-in log
helper to log the value of iterator
.
This will log undefined
for each iteration between the from
and to
arguments to our for
helper.
This is because there is no iterator
variable defined within the context of our block. The context for the block is determined by the argument passed to the invocation of block.fn
within our for
helper. In this case, the value is i
- the current iteration of our for loop.
This means that the execution context for the block has a single value, a number. We can access this value with the this
keyword. Our template becomes:
{{#for iterator endingLink iteratorInc}}
{{log this}}
{{/for}}
Which now logs a sequence of numbers, for example: 1, 2, 3, 4, 5
.
This is good, but when we transfer this to your actual block body implementation, we still have a problem.
The {{#ifCond iterator '===' page}}
will never be met because there is no page
in our block context and so it is always undefined
. We need to get the page
value from the parent context.
Fortunately, Handlebars provides a way for us to "step up" to a higher context level to grab a value: ../
. Therefore, the expression we need in our template is: ../page
.
Finally, the non-selectedLink
anchor (<a href="/?page={{this}}">{{this}}</a>
) is going to render for each iteration of our loop, causing a duplicate of the selected page link. We would want to use an {{else}}
to prevent the duplication.
Our template becomes:
{{#for iterator endingLink iteratorInc}}
{{#ifCond this '===' page}}
<a href="/?page={{this}}">{{this}}</a>
{{else}}
<a href="/?page={{this}}">{{this}}</a>
{{/ifCond}}
{{/for}}
I have created a fiddle for reference.