2

I'm working on an angular 4 project calling a json through a service, everything works very well exept for a single thing, my json has the following simplified structure for understanding the problem:

{
  "animals" [

   {
    "name" : "dog"
    "subgroup": "vertebrate"
    "class" : "mammal"
   },
   {
    "name" : "pig"
    "subgroup": "vertebrate"
    "class" : "mammal"
   },
   {
    "name" : "cat"
    "subgroup": "vertebrate"
    "class" : "mammal"
   },
   {
    "name" : "snake"
    "subgroup": "vertebrate"
    "class" : "reptile"
   },
   {
    "name" : "lizzard"
    "subgroup": "vertebrate"
    "class" : "reptile"
   },
   {
    "name" : "crocodile"
    "subgroup": "vertebrate"
    "class" : "reptile"
   },
 ]
}

and i want to iterate ONLY the objects with the "class" : "reptile"

i made this structure:

  <div class="col-12 mb-3" *ngFor="let reptiles of animals">
    <div *ngIf = "reptiles.class == reptile">
      <div class="row">
        <div class="col-12">
          <h5 class="py-3 bg-dark text-white pl-3 mx-0 mb-3">{{reptiles.name}}</h5>
          <p class="py-3 bg-dark text-white font-weight-light pl-3 m-0">{{reptiles.class}}</p>
        </div>
      </div>
    </div>
  </div>

but what happens is that it iterates three empty

<div class="col-12 mb-3" *ngFor="let reptiles of animals">
</div>

corresponding to the mammals, and i want that objects not to iterate at all, i want to iterate only the objects with the class "reptile". how can i achieve that?

Carlos Pisarello
  • 1,254
  • 5
  • 20
  • 39

3 Answers3

3

The easy fix is to use ng-container instead of a div to iterate:

<ng-container *ngFor="let reptiles of animals">
    <div class="col-12 mb-3" *ngIf="reptiles.class == reptile">
        <div>
            <!-- ... -->
        </div>
    </div>
</ng-container>

Of course the template still iterates over these entries now, but it will not create any DOM node for it whatsoever (the magic of ng-container).

Possibly a better fix would be to instead filter in your component and only pass the data you want to display to the template:

// In your controller after receiving the animals data:
this.reptiles = this.animals.filter(a => a.class === "reptile");

// Template
<div *ngFor="let reptile of reptiles">...</div>

You can also write a filterBy pipe or take one from an existing library such as ngx-pipes. But beware that Angular discourages that as it easily becomes a performance pitfall.

Ingo Bürk
  • 19,263
  • 6
  • 66
  • 100
  • 1
    `ngFor` should be written on `ng-container` or it will result into same problem – Dhyey Dec 20 '17 at 14:38
  • the easy fix didn't work, it still iterates the empty divs of the mammals because the condition of the ng-container is aplied after the iterations, it iterates all the objects first and then applies the condition to show or not to show the ng-container, how could i filter that data in the component? i just started working with angular a few months ago and there's a lot of things i still don't know. – Carlos Pisarello Dec 20 '17 at 14:40
  • @CarlosPisarello I had a mistake before, the answer is now updated. – Ingo Bürk Dec 20 '17 at 14:40
1

I think that you can use this solution

Just filter by class property:

filterItemsOfType(type){
    return this.items.filter(x => x.class == type);
}

Cheers,

@carlosrojas_o

Carlos Rojas
  • 5,547
  • 2
  • 14
  • 13
0

you just need to filter your data in component like this:

this.filteredAnimals = this.animals.filter(animal => animal.class === "reptile"); // now use filteredAnimals in html template

Hope it will help

Sandip Jaiswal
  • 3,428
  • 2
  • 13
  • 15