1

I have a list of items that contains country and city names like following and I want to show the serial number for a specific type of item in list.

items = [
    {'type': 'Country', 'title': 'Armenia',  },
    {'type': 'City', 'title': 'Kapan'   },
    {'type': 'City', 'title': 'Goris'   },
    {'type': 'City', 'title': 'Hats’avan' },

    
    {'type': 'Country', 'title': 'Angola'  },
    {'type': 'City', 'title': 'Catabola'  },
    {'type': 'City', 'title': 'Camacupa' },
    {'type': 'City', 'title': 'Caluquembe'  },

    {'type': 'Country', 'title': 'Argentina'  },
    {'type': 'City', 'title': 'San Vicente'  },
    {'type': 'City', 'title': 'Santa Elena'  },
    {'type': 'City', 'title': 'Retiro'  },
  ];


<div>
    <p *ngFor="let item of items; let i=index;">
        <b>{{i+1}}.</b>&nbsp;&nbsp;{{item.title}} &nbsp; ({{item.type}})
    </p>
</div>

it is showing like this:

1.  Armenia   (Country)

2.  Kapan   (City)

3.  Goris   (City)

4.  Hats’avan   (City)

5.  Angola   (Country)

6.  Catabola   (City)

7.  Camacupa   (City)

8.  Caluquembe   (City)

9.  Argentina   (Country)

10.  San Vicente   (City)

11.  Santa Elena   (City)

12.  Retiro   (City)

But I want to display like this: ( Serial number should display only with city name )

    Armenia   (Country)

1.  Kapan   (City)

2.  Goris   (City)

3.  Hats’avan   (City)

    Angola   (Country)

4.  Catabola   (City)

5.  Camacupa   (City)

6.  Caluquembe   (City)

    Argentina   (Country)

7.  San Vicente   (City)

8.  Santa Elena   (City)

9.  Retiro   (City)

Here is the stackblitz where I tried

https://stackblitz.com/edit/angular-serial-number-dynamic-conditional?file=src/app/app.component.html

4 Answers 4

1

You don't have that "serial" property. So Although you could do:

<b *ngIf="item.type == 'City'" >{{i+1}}.</b>

It's going to show the index, and not the "rank" which I think is a more correct term here.

instead, what you want appears to be more of calling a function and using that value:

 ngAfterViewInit(){
   this.lastRank = -1;
 }

  getNextRank(){   
    this.lastRank++;   
    return this.lastRank;
  }

ts:

<b *ngIf="item.type == 'City'"> {{getNextRank()}} </b>

And while this gets you closer, it has some fundamental problems in Angular. I wouldn't do it, even if it "makes sense" as someone newer to Angular.

Instead, the better route would be to use Hidden, but push the correct property onto the array:

import { AfterViewChecked, AfterViewInit,  Component, OnInit,  VERSION } from "@angular/core";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements AfterViewInit {
  

 ngAfterViewInit(){
   let lastRank = 0;

   this.items.forEach(e => {
    if(e.type == "City"){
      lastRank++;
      e.cityRank = lastRank;
    }
   });
 }


  items: Place[] = [
    { type: "Country", title: "Armenia" },
    { type: "City", title: "Kapan" },
    { type: "City", title: "Goris" },
    { type: "City", title: "Hats’avan" },

    { type: "Country", title: "Angola" },
    { type: "City", title: "Catabola" },
    { type: "City", title: "Camacupa" },
    { type: "City", title: "Caluquembe" },

    { type: "Country", title: "Argentina" },
    { type: "City", title: "San Vicente" },
    { type: "City", title: "Santa Elena" },
    { type: "City", title: "Retiro" }
  ];
}

export class Place 
{
  type: string;
  title: string;
  cityRank?: number;
}

And the HTML:

<div>
  <p *ngFor="let item of items; let i=index;">
    <b [hidden]="item.type=='Country'"> {{item.cityRank}} </b>
  &nbsp;&nbsp;{{item.title}} &nbsp; ({{item.type}})
  </p>
</div>

updated stackblitz

And result:

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

Any particular reason for adding the increment logic in "ngAfterViewInit" event instead of "ngOnInit" event?
@VimalPatel none at all!
0

Approach 1:

There are many ways to hide the serial numbers. Simplest is to add a [hidden] attribute to hide it when item type is country. Like below.

[hidden]="item.type=='Country'"

Approach 2:

If you want to keep the indentation same create a class name as hide like below and apply that class using ngClass if condition is true.

.hide {
  visibility: hidden;
}

<b [ngClass]="{'hide':item.type=='Country'}">

2 Comments

no, the serial number is then skipping the serial of country
so you dont want to skip the numbers?
0

Here is the solution added a new getter


  get __items() {
    let i = 0;
    let newItem: { type: string; title: string; counter: number };
    return this.items.map(item => {
      if (item.type === "City") {
        i++;
      }
      newItem = Object.assign({}, item, { counter: i });
      return newItem;
    });
  }

and use it in template

<div>
    <p *ngFor="let item of __items">
        <b *ngIf="item.type==='City'">{{item.counter}}.</b>&nbsp;&nbsp;{{item.title}} &nbsp; ({{item.type}})
    </p>
</div>

enter image description here

stackblitz link https://stackblitz.com/edit/angular-serial-number-dynamic-conditional-xsft3e

2 Comments

Catabola should start with 4. not 5. it seems 4 is missing..
fixed it..please check
0

You could use the ol html tag and render only cities within the li tag.

<div>
    <ol style="list-style-type: decimal;">
        <ng-container *ngFor="let item of items">
            <li *ngIf="item.type === 'City'; else country">
                {{ item.title }}
            </li>
            <ng-template #country>
                {{ item.title }}
            </ng-template>
        </ng-container>
    </ol>
</div>

See forked stackblitz:

https://stackblitz.com/edit/angular-serial-number-dynamic-conditional-esgwc3?file=src/app/app.component.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.