I want to use a div
as a container. Within that container I'd like to populate up to 3 elements with *ngFor
or *ngRepeat
. After that limit is reached I'd like a new instance of the parent div
to be generated to continue populating the data.
So far I've tried this
<!-- I want to create a new instance of this once 3 elements are generated in it -->
<div *ngFor="let link of homeIntroData?.links; let i=index;" class="">
<!-- This is what I want to generate up to 3 times before a new container is generated -->
<div *ngIf="i<3" class="" >
<div class="card">
<p class="" routerLink="" routerLinkActivate="">
{{link.link}}
</p>
</div>
</div>
I came across this Angular 2: how to apply limit to *ngFor?
which I thought originally was the answer, but it just limits the element to 3 entries, plus it applies to the entire container rather than the element inside of it. I want them to span across the screen horizontally in rows of 3, not 1 row of all of them.
So far I've discovered I have to move the *ngFor
and *ngIf
coding down into the child element like this
<div class="">
<div *ngFor="let link of homeIntroData?.links; let i=index;" class="">
<div *ngIf="i<3" class="card">
<p class="" [routerLink]="" routerLinkActivate="">
{{link.link}}
</p>
</div>
</div>
</div>
This keeps it all in a row like I want it, but I can't wrap my head around how to go about telling Angular to create a new instance of the parent and continue populating into it.
So far I came across this https://github.com/michaelbromley/ng2-pagination which is for pagination, but it essentially does what I want it to do somehow. I figured I'd basically have to somehow tell it to show 2 pages at the same time. The more I read into it the more I got confused in terms of trying to figure out how to use it the way I need to use it.
So far I'm thinking I need to create a custom pipe to bind to an *ngIf
in the parent div
in order to tell it to do what I want it to do once it has 3 child elements. Before I embark on that journey I'd like to know if there's any possible way to do this with Angular 2 out of the box. If not, how can I achieve this? Thanks in advance.
UPDATE
The plunker posted by yurzui
in the comments is EXACTLY what I need to do, which you can view here https://plnkr.co/edit/q9olLVsEcGrskv8oQkV7?p=preview. I went about applying it to my site and bumped into a few problems.
For starters, I'm using firebase as my database with angularfire2. Which means I have one huge object with other large objects with a few objects that are actually arrays of the same type of data. Because of this the only way I have the binding working properly is like this.
<div *ngFor="let link of homeIntroData$?.links" class="row home_link_container">
<div *ngFor="let link of pipe" class="col-4">
<div class="card">
<p class="home_link" [routerLink]="'/home/'+link.val" routerLinkActivate="active">
{{link.link}}
</p>
</div>
</div>
</div>
I can't say
<div *ngFor="links of homeIntroData$">
because homeIntroData$
itself isn't an array. Where in the plunker the "Great Yurzui" concocted it's set up like this
<div *ngFor="let chunk of items | chunks: 3" class="row">
<div *ngFor="let item of chunk" class="card">
<p>
{{item}}
</p>
</div>
</div>
Which I haven't even begun to dig into getting the pipe to work yet because I'm stuck on how to get my data in a way that will allow me to apply this. The important thing here is being able to load the links
into a parent element with a limit of 3 children, then a child that loads link
3 times per parent like in the plunker.
I came across this post https://github.com/angular/angular/issues/6392 which talks about the issue of the data not being an array and and suggesting breaking that data down into chunks we can link to directly. So I modified the class of my component like this
export class HomeIntroComponent implements OnInit {
private homeIntroData$: FirebaseObjectObservable<any>;
//added this to call in the template
private homeIntroLinks$: FirebaseListObservable<any>;
constructor(private _homeService: HomeService) {}
ngOnInit() {
this._homeService.getHomeIntroData().subscribe(HomeIntroData =>{
this.homeIntroData$ = HomeIntroData;
//used the same class from the service to go directly to links
this.homeIntroLinks$ = HomeIntroData.links;
console.log(this.homeIntroLinks$);
});
}
}
Seeing that I have to use {{link.link}}
in the binding to get everything to show up I figured I could get away with making the child element like this
<div *ngFor="let link of link" class="col-4">
<div class="card">
<p class="home_link" [routerLink]="'/home/'+link.val" routerLinkActivate="active">
{{link}}
</p>
</div>
</div>
but of course I get an error about [object object]
again. So I really can't figure out how to call my data to work with this. The exported JSON
for the homeIntroData
is
"home_intro" : {
"links" : [ {
"link" : "I need to expand my current brand.",
"val" : "expand"
}, {
"link" : "I need to re-create my Brand.",
"val" : "recreate"
}, {
"link" : "I need to build a Brand for my new Business.",
"val" : "new-business"
}, {
"link" : "I need to build a Brand for my new product.",
"val" : "new-product"
}, {
"link" : "I have a technical difficulty that requires an Artist.",
"val" : "tech-difficulty"
} ]
}
Another thing is if you look in the plunker you'll see Yurzui added chunk
to the binding like this
<div *ngFor="let chunk of items | chunks: 3" class="row">
<div *ngFor="let item of chunk" class="card">
<p>
{{item}}
</p>
</div>
</div>
If you look through the rest of the app.ts
file you'll see it's not defined anywhere. There's chunks
in the pipe, and chunkSize
in the PipeTransform
, but not chunk
. I even played around with it and changed it's name into something totally different that didn't have anything to do with a chunk in any way and it STILL WORKED!!!. Why?, how?