web-dev-qa-db-fra.com

Comment filtrer les éléments à l'intérieur de la boucle «ngFor», en fonction de la chaîne de propriété de l'objet

J'ai besoin de filtrer les éléments à l'intérieur d'une boucle ngFor, en changeant la catégorie dans une liste déroulante. Par conséquent, lorsqu'une catégorie particulière est sélectionnée dans la liste, elle ne doit répertorier que les éléments contenant cette même catégorie.

Modèle HTML:

<select>
  <option *ngFor="let model of models">{{model.category}}</option>
</select>

<ul class="models">
  <li *ngFor="let model of models" (click)="gotoDetail(model)">
  <img [src]="model.image"/>
  {{model.name}},{{model.category}}
  </li>
</ul>

Tableau des éléments:

export var MODELS: Model[] = [
{ id: 1, 
  name: 'Model 1', 
  image: 'img1', 
  category: 'Cat1', 
},

{ id: 2, 
  name: 'Model 2', 
  image: 'img2', 
  category: 'Cat3',
},

{ id: 3, 
  name: 'Model 3', 
  image: 'img3', 
  category: 'Cat1',
},
{ id: 4, 
  name: 'Model 4', 
  image: 'img4', 
  category: 'Cat4',
},

...
];

En outre, la liste déroulante contient des noms de catégorie répétés. Il lui est nécessaire de ne lister que les catégories uniques (chaînes).

Je sais que la création d'un tuyau personnalisé serait la bonne façon de le faire, mais je ne sais pas comment en écrire un.

Plunker: http://plnkr.co/edit/tpl:2GZg5pLaPWKrsD2JRted?p=preview

11
gundra

Voici un exemple de pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'matchesCategory'
})
export class MathcesCategoryPipe implements PipeTransform {
    transform(items: Array<any>, category: string): Array<any> {
        return items.filter(item => item.category === category);
    }
}

Pour l'utiliser:

<li *ngFor="let model; of models | matchesCategory:model.category" (click)="gotoDetail(model)">

===== pour l'exemple plunkr ====

Vous avez besoin que vos modifications choisies se reflètent dans certaines variables

Définissez d'abord dans votre classe un membre:

selectedCategory: string;

puis mettez à jour votre modèle:

<select (change)="selectedCategory = $event.target.value">
   <option *ngFor="let model of models ">{{model.category}}</option>
</select>

enfin, utilisez le tuyau:

  <li *ngFor="let model; of models | matchesCategory:selectedCategory" (click)="gotoDetail(model)">

==== commentaires après avoir vu le plongeur ====

J'ai remarqué que tu avais utilisé la promesse. Angular2 est plus orienté rxjs. Donc la première chose que je changerais est à votre service, remplacez:

getModels(): Promise<Model[]> {
  return Promise.resolve(MODELS);
}

à:

getModels(): Observable<Array<Model>> {
  return Promise.resolve(MODELS);
}

et

getModels(id: number): Observable<Model> {
  return getModels().map(models => models.find(model.id === id);
}

puis dans votre ModelsComponent

models$: Observable<Array<Model>> = svc.getModels();
uniqueCategories$: Observable<Array<Model>> = this.models$
  .map(models => models.map(model => model.category)
  .map(categories => Array.from(new Set(categories)));

Vos options deviendront:

     <option *ngFor="let category; of uniqueCategories$ | async">{{model.category}}</option>

et votre liste:

      <li *ngFor="let model; of models$ | async | matchesCategory:selectedCategory" (click)="gotoDetail(model)">

Il s'agit d'une solution très provisoire car vous avez de nombreux doublons et vous continuez à interroger le service. Prenez cela comme point de départ et interrogez le service une seule fois, puis dérivez des valeurs spécifiques du résultat que vous avez obtenu.

Si vous souhaitez conserver votre code, implémentez simplement un UniqueValuesPipe, sa transformation obtiendra un seul paramètre et le filtrera pour renvoyer des catégories uniques à l'aide de la fonction Array.from(new Set(...)). Vous devrez cependant le mapper aux chaînes (catégories) en premier.

18
Meir