Hi all,
I am trying to create a grid of items
, with 3 columns and as many rows as needed. I have a list of items
to iterate through as you can see below, but instead of repeating the same item
on each row for all 3 columns, how can I display the next item
?
Thank you
<ion-list>
<ion-item *ngFor="let item of items">
<ion-row>
<ion-col width-33>
<p>{{item.name}}</p>
</ion-col>
<ion-col width-33>
<p>{{item.name}}</p>
</ion-col>
<ion-col width-33>
<p>{{item.name}}</p>
</ion-col>
</ion-row>
</ion-item>
</ion-list>
For example:
| item1 | item2 | item3 |
| item4 | item5 | item6 |
| item7 |
p.s. I don’t know how big the list of items
will be (i.e. it is dynamic).
This SO question looks exactly like your situation.
Thanks rapropos, that looks exactly what I am looking for too.
Except, how do you fix the typscript errors for?
this.rows = Array.from(Array(Math.ceil(this.subCategoryModels.length / 3)).keys());
errors:
[ts]
Property 'from' does not exist on type 'ArrayConstructor'.
any
and
[ts]
Property 'keys' does not exist on type 'any[]'.
any
Is Array
not an ArrayConstructor
?
That sounds like an ES5/ES6 problem. I get no typescript errors dropping that line into a stock Ionic scratch project.
Yes, I think it is an ES6 issue.
I try the following, which gives no errors:
this.rows = Object.keys(Array(Math.ceil(this.subCategoryModels.length / 3)));
However, this.rows
is empty, even though subCategoryModels.length
= 3.
Looks like my javascript is incorrect. What should this.rows
contain?
public users = [
{ name: 'Jilles', age: 21 },
{ name: 'Todd', age: 24 },
{ name: 'Lisa', age: 18 }
];
let rows = Array.from(Array(Math.ceil(this.users.length / 2)).keys());
> rows;
[0, 1]
1 Like
rapropos, are you using Ionic 2? Does that mean you have ES6? I am using Ionic 2, and would have thought it used ES 6.
Yes, that’s an Ionic 2 project using the standard beta 10 browserify build. Normally I use webpack, but for testing stuff like this I just have a scratch tabs project. I do see typings for es6-shim; that may be what is making Array.from
work. I don’t recall adding them manually, so I expect the project generator did that.
I can get the following to work with ES5. It is not as as elegant, but will use it for now until I can find a better solution.
for (var index = 0; index < Math.ceil(this.subCategoryModels.length / 3); index++) {
this.rows.push(index);
}
Hi All,
Angular’s ngFor
is not the same as JavaScript’s for
, and when it’s treated as a simple iterator, code will get m-e-s-s-y!
Try this code instead.
HTML code
<ion-grid>
<ion-row *ngFor="let trio of getTriples()">
<ion-col *ngFor="let item of trio">
<ion-item>{{ item }}</ion-item>
</ion-col>
</ion-row>
</ion-grid>
TS code
export class HomePage {
myList: any[];
constructor(private navCtrl: NavController) {
this.myList = [];
for (let i=0; i<20; i++) {
this.myList.push(i);
}
}
getTriples() {
let triples = [];
let length = this.myList.length;
for (let i = 0; i < length; i += 3) {
let trio = [];
trio.push(this.myList[i]);
if (i + 1 < length) {
trio.push(this.myList[i + 1]);
}
if (i + 2 < length) {
trio.push(this.myList[i + 2]);
}
triples.push(trio);
}
return triples;
}
}
Here are some benefits of coding like this:
- this maintains a clear and necessary break between code for the layout and code for the app logic
- this is worlds easier to understand with very little extra memory / run-time (Will you remember what you meant to do with that math statement when you glance at it 2 months from now?)
- easier to edit & change in the future
- unit testing is not as easy in the coding style of the SO link above
- you do not need to build messy logic into the HTML file
- you do not need to change the internal structure of your list of items in order to achieve the layout you’re looking for
I hope this helps!
Ryan
2 Likes
Can anyone please tell me how to fix this?
When I run this code, how can I pass item
to the function:
<ion-row *ngFor="let i of rows">
<ion-col *ngFor="let item of categoryModels | slice:(i*3):(i+1)*3" (click)="itemTapped(item)" width-33>
<div class="row responsive-md">
<img src="data:image/png;base64,{{item.icon}}" height="75" width="75" />
<p>{{item.name}}</p>
</div>
</ion-col>
</ion-row>
and
itemTapped(event: Event, categoryModel: CategoryModel) {
console.log('itemTapped: '+categoryModel);
this.nav.push(SubCategoryPage, {
categoryModel: categoryModel
});
}
outputs:
itemTapped: undefined
I also try the following with the same result:
<img src="data:image/png;base64,{{item.icon}}" height="75" width="75" (click)="itemTapped(item)"/>
I also try with ryanslogsdon’s example with the same result:
<ion-row *ngFor="let trio of getTriples()">
<ion-col *ngFor="let item of trio">
<div class="row responsive-md">
{{ formatCategories(item) }}
<img src="data:image/png;base64,{{item.icon}}" height="75" width="75" (click)="itemTapped(item)" />
<p>{{item.name}}</p>
</div>
</ion-col>
</ion-row>
SOLVED: silly mistake on my part. itemTapped
signiture was incorrect
itemTapped(categoryModel: CategoryModel) {
console.log('itemTapped: ' + categoryModel);
this.nav.push(SubCategoryPage, {
categoryModel: categoryModel
});
}
1 Like
Thanks Ryan! It works! But i need a little edit in
<ion-col style="width:33%">