louis
louis

Reputation: 11

ngFor removing duplicates in observable list

I want to remove duplicates values in observable list. Only in template, not changing component!

Using the index I want removing duplicates values in double *ngFor.

Is there any way?

<div class="order-list-row" *ngFor="let list of sandbox.orderList$ | async;">
    <div class="olr-header flex">
        <div class="olrh-lft flex">
            <div class="olrh-lft-col">
                <h5>주문코드</h5>
                <p>{{list.orderPrefixId}}</p>

I want to skip the values(list.orderPrefixId) ​​that have already been printed by applying a condition(using index)

Upvotes: 1

Views: 595

Answers (3)

H3AR7B3A7
H3AR7B3A7

Reputation: 5261

I realize you asked for a solution in the template, but I will give you 2 sensible solutions. One of which isn't really in the template, but it preserves the original observable just as well:

obs$: Observable<number[]> = of([1, 2, 3, 3, 4, 4, 4, 5]);

filteredObs$ = this.obs$.pipe(
  map((arr) => {
    return new Set(arr);
  })
);

In template:

<p *ngFor="let n of filteredObs$ | async">
  {{ n }}
</p>

If you want the filtering to happen in the template, you can create a function:

filterArray(arr: number[]): number[] {
  return Array.from(new Set(arr));
}

In template:

<p *ngFor="let n of filterArray(obs$! | async)">
  {{ n }}
</p>

I just used a number[] in this example but the idea is the same for objects, the mapping would just be a little more complex. There are plenty examples for that on the net, but if you need help with that just ask.

Here's my example in a StackBlitz.

Upvotes: 1

Eliseo
Eliseo

Reputation: 57941

Really the best approach is create a new observable with the uniques values

if your sandbox.orderList$ return, e.g. some like

[{id:0},{id:1},{id:2},{id:2},{id:3},{id:0},...]

You can define

orderListUnique$=this.sandbox.orderList$.pipe(
     map((res:any[],i:number)=>
          res.reduce((a,b)=>a.find(x=>x.id==b.id)?a:[...a,b],[])
  ))

And use orderListUnique$ |async

only for fun

If your list is ordered you can write some "bizarro" like

<ng-container *ngIf="{ values: values$ | async } as values">
  <ng-container *ngFor="let value of values.values; let i = index">
    <ng-container *ngIf="i == 0 ? null : '' + values.values[i - 1].id as old">
      <p *ngIf="value.id != old">
        {{ value.id }}
      </p>
    </ng-container>
  </ng-container>
</ng-container>

If your list is not ordered, you need to have an array with the key to order, e.g. if you has a variable "indexValues"

obs$=observable.pipe(
    tap((res:any[])=>this.indexValues=res.map(x=>x.id)))

And use

<ng-container *ngFor="let value of objValues$ | async; let i = index">
  <ng-container *ngIf="indexValues.indexOf(value.id) == i">
    <p>
      {{ value.id }}
    </p>
  </ng-container>
</ng-container>

You can see the approach in this stackblitz

Upvotes: 0

adedayojs
adedayojs

Reputation: 136

You could use a directive or better still logic like this are meant to stay in your component file. Doing this kind of Filtering in your template file is a bad design it self.

Subscribe to the observable in your component file and perform your filtering therein

Upvotes: 1

Related Questions