Iterating over basic “for” loop using Handlebars.js - handlebars.js

I’m new to Handlebars.js and just started using it. Most of the examples are based on iterating over an object. I wanted to know how to use handlebars in basic for loop.
Example.
for(i=0 ; i<100 ; i++) {
create li's with i as the value
}
How can this be achieved?

There's nothing in Handlebars for this but you can add your own helpers easily enough.
If you just wanted to do something n times then:
Handlebars.registerHelper('times', function(n, block) {
var accum = '';
for(var i = 0; i < n; ++i)
accum += block.fn(i);
return accum;
});
and
{{#times 10}}
<span>{{this}}</span>
{{/times}}
If you wanted a whole for(;;) loop, then something like this:
Handlebars.registerHelper('for', function(from, to, incr, block) {
var accum = '';
for(var i = from; i < to; i += incr)
accum += block.fn(i);
return accum;
});
and
{{#for 0 10 2}}
<span>{{this}}</span>
{{/for}}
Demo: http://jsfiddle.net/ambiguous/WNbrL/

Top answer here is good, if you want to use last / first / index though you could use the following
Handlebars.registerHelper('times', function(n, block) {
var accum = '';
for(var i = 0; i < n; ++i) {
block.data.index = i;
block.data.first = i === 0;
block.data.last = i === (n - 1);
accum += block.fn(this);
}
return accum;
});
and
{{#times 10}}
<span> {{#first}} {{#index}} {{#last}}</span>
{{/times}}

If you like CoffeeScript
Handlebars.registerHelper "times", (n, block) ->
(block.fn(i) for i in [0...n]).join("")
and
{{#times 10}}
<span>{{this}}</span>
{{/times}}

This snippet will take care of else block in case n comes as dynamic value, and provide #index optional context variable, it will keep the outer context of the execution as well.
/*
* Repeat given markup with given times
* provides #index for the repeated iteraction
*/
Handlebars.registerHelper("repeat", function (times, opts) {
var out = "";
var i;
var data = {};
if ( times ) {
for ( i = 0; i < times; i += 1 ) {
data.index = i;
out += opts.fn(this, {
data: data
});
}
} else {
out = opts.inverse(this);
}
return out;
});

Couple of years late, but there's now each available in Handlebars which allows you to iterate pretty easily over an array of items.
https://handlebarsjs.com/guide/builtin-helpers.html#each

Related

Typescript - multidimensional array initialization

I'm playing with Typescript and I wonder, how to properly instantiate and declare multidimensional array. Here's my code:
class Something {
private things: Thing[][];
constructor() {
things = [][]; ??? how instantiate object ???
for(var i: number = 0; i < 10; i++) {
this.things[i] = new Thing[]; ??? how instantiate 1st level ???
for(var j: number = 0; j< 10; j++) {
this.things[i][j] = new Thing(); ??? how instantiate 2nd lvl item ???
}
}
}
}
Can you give me any hint about selected places?
You only need [] to instantiate an array - this is true regardless of its type. The fact that the array is of an array type is immaterial.
The same thing applies at the first level in your loop. It is merely an array and [] is a new empty array - job done.
As for the second level, if Thing is a class then new Thing() will be just fine. Otherwise, depending on the type, you may need a factory function or other expression to create one.
class Something {
private things: Thing[][];
constructor() {
this.things = [];
for(var i: number = 0; i < 10; i++) {
this.things[i] = [];
for(var j: number = 0; j< 10; j++) {
this.things[i][j] = new Thing();
}
}
}
}
Here is an example of initializing a boolean[][]:
const n = 8; // or some dynamic value
const palindrome: boolean[][] = new Array(n)
.fill(false)
.map(() =>
new Array(n).fill(false)
);
If you want to do it typed:
class Something {
areas: Area[][];
constructor() {
this.areas = new Array<Array<Area>>();
for (let y = 0; y <= 100; y++) {
let row:Area[] = new Array<Area>();
for (let x = 0; x <=100; x++){
row.push(new Area(x, y));
}
this.areas.push(row);
}
}
}
You can do the following (which I find trivial, but its actually correct).
For anyone trying to find how to initialize a two-dimensional array in TypeScript (like myself).
Let's assume that you want to initialize a two-dimensional array, of any type. You can do the following
const myArray: any[][] = [];
And later, when you want to populate it, you can do the following:
myArray.push([<your value goes here>]);
A short example of the above can be the following:
const myArray: string[][] = [];
myArray.push(["value1", "value2"]);
Beware of the use of push method, if you don't use indexes, it won't work!
var main2dArray: Things[][] = []
main2dArray.push(someTmp1dArray)
main2dArray.push(someOtherTmp1dArray)
gives only a 1 line array!
use
main2dArray[0] = someTmp1dArray
main2dArray[1] = someOtherTmp1dArray
to get your 2d array working!!!
Other beware! foreach doesn't seem to work with 2d arrays!

Flex how to use callLater?

In my flex mobile application, I have a loop running for over 100 iterations. In each iteration I'm updating some properties of specific Label(s). Since the loop is time consuming, I need to update the screen and display intermediate results at each iteration. How can I break the loop and refresh the display list?
function theFunction():void{
for var i:int = 0; i < n; i++{
doBusyStuff();
label_1.text = "iteration"+" i";
}
}
In that situation, I prefer to use flash.utils.setTimeout()
import flash.utils.setTimeout;
function theFunction(limit:int, current:int = 0):void
{
if (current >= limit)
return;
doBusyStuff();
label_1.text = "iteration "+ current.toString();
setTimeout(theFunction, 0, limit, current+1);
}
However, both setTimeout() and callLater() depend on the tick or the frame rate, meaning that they won't do as fast as they can. So if you also want it to run faster, you should have it run a few loops per each call.
Another solution, similar to Chaniks' answer, uses DateTime to check how long the loop has been running on each iteration. Once it detects that it's been running for too long, it ends the loop and picks up again on the next Frame.
var i:int;
function callingFunction():void {
i = 0;
stage.addEventListener(Event.ENTER_FRAME, theFunction);
}
function theFunction(e:Event):void {
var time:DateTime = new DateTime();
var allowableTime:int = 30; //Allow 30ms per frame
while ((new DateTime().time - time.time < allowableTime) && i < n) {
doBusyStuff();
i++;
}
if (i >= n) {
stage.removeEventListener(Event.ENTER_FRAME, theFunction);
}
label_1.text = "iteration"+" i";
}
There are several methods to force redraw of components:
invalidateDisplayList();
invalidateProperties();
invalidateSize();
Just use whatever you need for your components inside a function and call it after your script using callLater(yourRedrawFunction);
EDIT: For example, in your case:
function theFunction():void{
for var i:int = 0; i < n; i++{
doBusyStuff();
label_1.text = "iteration"+" i";
}
callLater(yourRedrawFunction);
}

Multi-dimensional Arrays in AS3

I am currently playing around with flex, I have C++ background, so I am not used to AS3.
The problem is in the main *.mxml file I have fx:script block and I try to define a multidimensional array like that:
public var Board:Array = new Array(25);
I use a function to initialize the 2d-array:
public function initBoard():void {
var i:int;
var j:int;
for (i = 0; i < 25; i++) {
Board[i] = new Array(40);
for (j = 0; i < 40; j++) {
Board[i][j] = 0;
}
}
}
This function gets called later on in the main loop to init and reset the "board" why doesn't it work. The only difference to the AS3 documentation is that it gets done in a function. Is there a scope problem?
Thanking you in anticipation,
Niklas Voss
P.S. I hope someone can tell me why it doesn't work and how to do it right...
You have i where there should be j.
for (j = 0; i < 40; j++) {
This should solve your problems.
for (j = 0; j < 40; j++) {
You don't need to define an array length in AS3 - I just use the [] operator for creating a new array. Also you used i where j was needed in the innermost for loop.
function initBoard():Array
{
var board:Array = [];
var i:int = 0;
var j:int;
for(i; i<25; i++)
{
board[i] = [];
j = 0;
for(j; j<40; j++)
{
board[i][j] = 0;
}
}
return board;
}
trace(initBoard());

How to create an object from 2 arrays?

So I hava array Links and array Params with same langth N
So what I need is to create an object where for each link from Links I will be able to see
param from Params
And than for example to be abble to call something like
for each( item in object)
if (item.param == "some value") {
// some code
} else...
How to do such thing (Code exaMple, please)
From Array: You could first build a list with elements composed of a item and a param (supposing the length is indeed the same for both lists)
var items:Array = new Array();
for(var i:uint = 0; i < links.length; i++) {
links:Array .push({link:links[i], param:params[i]});
}
You can then filter them easily:
items.forEach(checkValue);
for(var i:uint = 0; i < items.length; i++) {
if (items[i].param == "some value") {
// some code
} else{
...
}
}

Declaring variables for limited scope at the head of the for loop

In Java, you sometimes do something like this:
for (int a = 1, b = 2; b < high;) {
if (b % 2 == 0) {
result += b;
}
int tmp = b;
b = a + b;
a = tmp;
}
Here, I used a for loop instead of a while loop to limit the scope of a and b.
But how can I achieve this in JavaFX? The for loop doesn't seem to offer this possibility. Do I have to use a while loop?
You could use the Java trick of anonymous blocks:
var high = 10;
{
var a = 0;
for (b in [1..high-1]) {
// this is fine
println("{a}");
}
}
// won't compile here
//println("{a}");
The are simmilar expressions in JavaFX but with those expressions you will get a double loop. According to this doc.

Resources