I am using Ember with Handlebars. I have a situation where I need to dynamically create new table rows after 3 iterations of an array.
<table>
{{#each items as |item itemIndex|}}
{{#if (compare (mod itemIndex 3) '===' 0)}}<tr>{{/if}}
<td>{{item.id}}</td>
{{#if (compare (mod itemIndex 3) '===' 2)}}</tr>{{/if}}
{{/each}}
</table>
For the sake of example, please assume that there will always be a factor of 3 in the items array. When I try to save this code, I'm getting a syntax error that there is no close tag matching the open tag. How can I dynamically create the and without the syntax error?
I'm using ember CLI version 2.9.1.
When you run the code snippet you have provided you will most likely encounter an error indicating Error while processing route: index Unclosed element tr (on line 8). Error: Unclosed element tr (on line 8).
This is because ember-template-compiler
does not know whether the rendering will result in a correct HTML
page as a result of rendering. What if the items
array is not divisible by 3; we will get an error in the runtime. In order to prevent that; ember-template-compiler
throws an error indicating an unclosed tr
tag.
So; what can be done to prevent this? You can create a computed property within your js file that simply returns the number of rows desired as follows:
rowCount: Ember.computed('items.length', function() {
return this.get('items.length')/3;
})
afterwards you can simply make use of range
helper provided by ember-composable-helpers and do the following within your template:
<table>
{{#each (range 0 rowCount) as |rowIndex|}}
<tr>
{{#each (range 0 3) as |columnIndex|}}
{{! `number` will go from 0 to 2}}
<td>
{{get (get-item-at-array-index items columnIndex rowIndex) 'id'}}
</td>
{{/each}}
</tr>
{{/each}}
</table>
The template code snippet provided above contains an helper named get-item-at-array-index
which simply finds the relevant item at the desired index position and it should have a simple code as follows:
export function getItemAtArrayIndex(params/*, hash*/) {
let array = params[0];
let index = params[1];
let rowIndex = params[2];
return array[index+rowIndex*3];
}
I have prepared the following twiddle for you that wraps up what I already explained above. By doing so; you will avoid the Unclosed element tr
error you get; since the tags will be closing explicitly and template compiler will not complain.