BorisMoore / jsrender

A lightweight, powerful and highly extensible templating engine. In the browser or on Node.js, with or without jQuery.
http://www.jsviews.com
MIT License
2.68k stars 340 forks source link

How to access iterator in range #338

Closed ghost closed 6 years ago

ghost commented 6 years ago

I have a data structure like this:

{
someNumber: 5,
someStuff:[ ... ... ]
}

I can create a row of items conditionally based on the value of someNumber by repeating the below snippet 5x (and manually setting i from 1 to 5)

     {{ if someNumber >= i }}
           <span>true</span>
     {{ else }}
           <span>false</span>
      {{ /if }}

Ideally I would like to use range for simplicity. Something like:

{{ range start=1 end=5 }}
     {{ if someNumber >= [iterator] }}
           <span>true</span>
     {{ else }}
           <span>false</span>
      {{ /if }}
{{ /range }}

I can't find the in loop variable to expose the iterator/index of the current iteration. I have tried #index and #data but both resolve as null/undefined in the loop. I also noticed that someNumber is less than 0 when using the construct.

Can you point me at some documentation that explains how to do this (jsviews.com isn't quite clear nor does it explain validating in loop), or offer some advice.

Thanks.

BorisMoore commented 6 years ago

You can access the iterator from within nested blocks using #getIndex(). See also http://jsviews.com/#views@itemview (and the rest of that documentation topic).

In the next update you will be able to do

{{for someStuff start=1 end=5}}
   <span>true</span>
{{/for}}

but it looks as if you need something like:

{{for someStuff}}
  {{if #getIndex() < 6}}
    <span>true</span>
  {else}}
    <span>false</span>
  {{/if}}
{{/for}}
ghost commented 6 years ago

Thanks, Boris. Below works for me to get the iterator in the range/for loop

{{range start=1 end=5}}
  {{if #getIndex() < 4 }}
    <span>true</span>
  {{/if}}
{{/range}}

but what I wanted was to be able to validate the iterator against someNumber. In this loop my data value someNumber equates to null, or is inaccessible.

Ideally I was hoping to achieve something like:

for (i = 1; i < 6; i++) {
  if(someNumber > i){
     //true
  }
}

I'll add some context. I'm using JsRender/JsViews to template a set of product cards:

<p>&nbsp;</p>
{{for Cards}}
  <div class="col-xxs-3">
    <div class="card carbon-panel product-card">
      <header class="badge-container hidden-xs hidden-sm">
        <span class="badge-slot"></span>
        <span class="badge-slot"></span>
        <span class="badge-slot"></span>
        <span class="badge-slot"></span>
        <span class="badge-slot"></span>
        <span class="pull-right">
          <i title="favourite?" class="glyphicon glyphicon-heart-empty favo-badge glyphicon-light"></i>
        </span>
      </header>

      <div class="img-container with-grow">
        <img src="{{>PhotoURL}}" class="img-responsive" />
      </div>

      <div class="product-rating">
        {{range start=1 end=5}}
          {{if ~Average >= #getIndex()}}
            <span class="glyphicon glyphicon-star rated"></span>
          {{else}}
            <span class="glyphicon glyphicon-star unrated"></span>
          {{/if}}
        {{/range}}
      </div>

      <div class="card-main-text">
        <p class="detail-block-text">
          <strong class="text-concat">
            <a class="carbon-text" href="{{>ProductNameUrl}}/{{>GUID}}">{{>ProductName}}</a>
          </strong>          
        </p>

        <p class="catalogue-reference">
          <span class="fontsize">
            {{>CatRef}}
          </span>
        </p>
        {{if StockLevel > 0}}
            <span><span class="available-stock">&bull;&nbsp;</span>{{>StockLevel}}</span>
        {{else}}
            <span><span class="nostock-text">&bull;&nbsp;</span>Out Of Stock</span>
        {{/if}}
        <p class="price-block">
            <span>
                <span class="availableprice-text">{{>MRRP.Symbol}}{{>MRRP.Value / Precision}}</span>
            </span>
        </p>

      </div>

    <footer class="card-footer">
      {{if StockLevel > 0}}
      <a class="btn btn-basket-add block-tall with-ripple">
        <i class="icon-add_shopping_cart"></i>
      </a>
      {{else}}
      <a class="btn btn-basket-add block-tall is-disabled" disabled>
        <i class="icon-add_shopping_cart"></i>
      </a>
      {{/if}}
    </footer>

      </div>  

  </div>
{{/for}}

For the better part, this renders nicely, but there is only 1 place that I stumble:

BorisMoore commented 6 years ago

Not sure why you put ~Average - (with a ~). Is it in the data or is it a helper? You don't show your data or JSON so I have no idea where Average is defined. I suppose it is higher up in the data object graph, in which case you need to read this: Accessing parent data

Maybe:

{{range start=1 end=5 ~Average=Average}}
  {{if ~Average >= #getIndex()}}
    <span class="glyphicon glyphicon-star rated"></span>
  {{else}}
    <span class="glyphicon glyphicon-star unrated"></span>
  {{/if}}
{{/range}}