Home > Blockchain >  My handlebars loop definition is not working
My handlebars loop definition is not working

Time:12-25

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.

  • Related