1

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?

Community
  • 1
  • 1
Optiq
  • 2,835
  • 4
  • 33
  • 68
  • 1
    Do you want to display 3 items per row? – yurzui Jan 24 '17 at 05:32
  • yes I do. I'm using bootstrap for responsiveness so they automatically center. – Optiq Jan 24 '17 at 05:34
  • 3
    Take a look at https://plnkr.co/edit/q9olLVsEcGrskv8oQkV7?p=preview – yurzui Jan 24 '17 at 05:35
  • GREAT!!!! I've been sitting here trying to wrap my head around it. Where are you getting the `chunk` property from though? I see `chunks` and `chunkSize`, but the only place I see `chunk` is in the html. I also noticed you exported the `app.module` on the bottom. Can't this be imported into a separate module as well and still work? – Optiq Jan 24 '17 at 11:30

0 Answers0