1

Say I have a simple component with a single property which holds an array of numbers:

class AppComponent {
    numbers: number[] = [1, 2, 3, 4, 5]
}

I want to display the odd numbers apart from the even numbers. Here's the template I currently have:

<div *ngFor="let number of numbers">
    <div>
        <h1>Odd Numbers</h1>
        <ul></ul>
    </div>
    <div>
        <h1>Even Numbers</h1>
        <ul></ul>
    </div>
</div>

The numbers should be listed as li items in the uls.

Also, if the array contains only even numbers, the 2nd div shouldn't be displayed.

Is this possible without storing 2 separate parts of the array?

Eyal
  • 1,649
  • 3
  • 25
  • 49

2 Answers2

2

Check this out :

<div *ngFor="let number of numbers;let i = index">
    <div *ngIf="(number%2 !== 0)" id="odd">
        <h1 *ngIf="i===0">Odd Numbers</h1>
        <ul>{{number}}</ul>
    </div>
</div>

<div *ngFor="let number of numbers;let i = index">
    <div *ngIf="(number%2 === 0)" id="even">
        <h1 *ngIf="i===1">Even Numbers</h1>
        <ul>{{number}}</ul>
    </div>
</div>

I would strongly suggest you to break the html further and create child component which can handle the array logic and render accordingly.

Implementing such logic will mess up your html code. As you are saying, you are not supposed to implement this logic on the component itself which has the number:number[]. Thats the core essence of component based pages

Shashank Vivek
  • 16,888
  • 8
  • 62
  • 104
  • By your design, I'd have the `h1` header "Odd Numbers" for every single odd number. I'd like to have a single header and all the odd numbers as `li` elements inside the `ul`. – Eyal Apr 22 '18 at 10:55
  • @AnDrOiD : in the same `*ngFor` iteration ? – Shashank Vivek Apr 22 '18 at 10:59
  • Didn't understand your question, sorry. – Eyal Apr 22 '18 at 11:00
  • It seems a bad approach if you are trying to do that in same `*ngFor` loop asyou'll have to write unnecessary code in html(which can be easily written on `ts` file) or without splitting the `array` in component itself – Shashank Vivek Apr 22 '18 at 11:05
  • Your answer works but it'd be nice if I wouldn't have to loop the array twice. My question is a simplified version of my original problem which contains a very long array. – Eyal Apr 22 '18 at 11:09
  • What if there's no other logic to the array? What if I want the numbers separated only in this component's template? – Eyal Apr 22 '18 at 11:24
  • @AnDrOiD: I tried `ng-content` to implement in your approach, put a bounty as well when couldn't make it work. i guess there is no other way than to use 2 loops. https://stackoverflow.com/questions/49988436/why-ng-content-selector-is-not-working-inside-ngfor/50148893. I hope this will help you in some ways as well. Upvoted ur question for helping me dive into this concept more. – Shashank Vivek May 03 '18 at 07:47
0

Given your markup, it seems you will have to process odd and even elements of array in separate loops. You can set up getters for odd and even numbers in your component, and use them in the template.

Component:

export class AppComponent {
  numbers: number[] = [1, 2, 3, 4, 5]

  get odds() {
    return this.numbers.filter( n => n % 2 == 1 )
  }

  get evens() {
    return this.numbers.filter( n => n % 2 == 0 )
  }
}

Template:

<div>
  <div>
      <h1>Odd Numbers</h1>
      <ul>
         <li *ngFor="let number of odds">
           {{number}}
         </li>
      </ul>
  </div>
  <div>
      <h1>Even Numbers</h1>
      <ul>
        <li *ngFor="let number of evens">
           {{number}}
         </li>
      </ul>
  </div>
</div>
Wand Maker
  • 18,476
  • 8
  • 53
  • 87
  • Looks like the most elegant solution yet. Why is such trivial thing not possible without looping the array twice? – Eyal Apr 23 '18 at 01:49