Comment filtrer un tableau avec TypeScript dans Angular 2?

109

L'héritage des données parent-enfant ng-2 a été une difficulté pour moi.

Ce qui semble être une solution pratique et efficace consiste à filtrer mon tableau total de données sur un tableau composé uniquement de données enfants référencées par un identifiant parent unique. En d'autres termes: l'héritage des données devient le filtrage des données par un identifiant parent.

Dans un exemple concret, cela peut ressembler à: filtrer un tableau de livres pour n'afficher que les livres avec un certain store_id.

import {Component, Input} from 'angular2/core';

export class Store {
  id: number;
  name: string;
}

export class Book {
  id: number;
  shop_id: number;
  title: string;
}

@Component({
  selector: 'book',
  template:`
    <p>These books should have a label of the shop: {{shop.id}}:</p>

    <p *ngFor="#book of booksByShopID">{{book.title}}</p>
  `
])
export class BookComponent {
  @Input()
  store: Store;

  public books = BOOKS;

  // "Error: books is not defined"
  // ( also doesn't work when books.filter is called like: this.books.filter
  // "Error: Cannot read property 'filter' of undefined" )
  var booksByStoreID = books.filter(book => book.store_id === this.store.id)
}

var BOOKS: Book[] = [
  { 'id': 1, 'store_id': 1, 'name': 'Dichtertje' },
  { 'id': 2, 'store_id': 1, 'name': 'De uitvreter' },
  { 'id': 3, 'store_id': 2, 'name': 'Titaantjes' }
];

TypeScript est nouveau pour moi, mais je pense que je suis sur le point de faire fonctionner les choses ici.

(Également écraser le tableau des livres d'origine pourrait être une option, puis utiliser *ngFor="#book of books".)

EDIT Se rapprocher, mais toujours donner une erreur.

//changes on top:
import {Component, Input, OnInit} from 'angular2/core';

// ..omitted

//changed component:
export class BookComponent implements OnInit {
  @Input() 
  store: Store;

  public books = BOOKS;

  // adding the data in a constructor needed for ngInit
  // "EXCEPTION: No provider for Array!"
  constructor(
    booksByStoreID: Book[];
  ) {}


  ngOnInit() {
    this.booksByStoreID = this.books.filter(
      book => book.store_id === this.store.id);
  }
}

// ..omitted
Code-MonKy
la source

Réponses:

205

Vous devez insérer votre code ngOnInitet utiliser le thismot - clé:

ngOnInit() {
  this.booksByStoreID = this.books.filter(
          book => book.store_id === this.store.id);
}

Vous en avez besoin ngOnInitcar l'entrée storene serait pas définie dans le constructeur:

ngOnInit est appelé juste après que les propriétés liées aux données de la directive ont été vérifiées pour la première fois et avant que l'un de ses enfants ait été vérifié. Il n'est appelé qu'une seule fois lorsque la directive est instanciée.

( https://angular.io/docs/ts/latest/api/core/index/OnInit-interface.html )

Dans votre code, le filtrage des livres est directement défini dans le contenu de la classe ...

Thierry Templier
la source
Logique. J'obtiens l'erreur "Erreur: ngOnInit n'est pas défini" après avoir ajouté votre morceau de code, importé OnInitet ajouté booksByStoreID = Book[];le composant.
Code-MonKy
Je pense que c'est plutôt:booksByStoreID: Book[];
Thierry Templier
Ça ne marche pas non plus. Dois-je mettre cela dans un constructeur peut-être? J'ai essayé ceci, puis j'obtiens une erreur en me plaignant du]
Code-MonKy
1
Merci! Le filtrage fonctionne parfaitement :) Un nouveau problème se pose cependant. Lorsque vous cliquez dans le composant parent pour qu'un autre magasin soit sélectionné, l'ancien store_id reste et la liste des livres reste la même ...
Code-MonKy
1
Excellent. félicitations pour 200 votes !!!
Amuk Saxena le
18

Vous pouvez consulter un exemple dans Plunker ici les filtres d'exemple de plunker

filter() {

    let storeId = 1;
    this.bookFilteredList = this.bookList
                                .filter((book: Book) => book.storeId === storeId);
    this.bookList = this.bookFilteredList; 
}
yaircarreno
la source
4

Pour filtrer un tableau quel que soit le type de propriété (c'est-à-dire pour tous les types de propriété), nous pouvons créer un tube de filtre personnalisé

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

@Pipe({ name: "filter" })
export class ManualFilterPipe implements PipeTransform {
  transform(itemList: any, searchKeyword: string) {
    if (!itemList)
      return [];
    if (!searchKeyword)
      return itemList;
    let filteredList = [];
    if (itemList.length > 0) {
      searchKeyword = searchKeyword.toLowerCase();
      itemList.forEach(item => {
        //Object.values(item) => gives the list of all the property values of the 'item' object
        let propValueList = Object.values(item);
        for(let i=0;i<propValueList.length;i++)
        {
          if (propValueList[i]) {
            if (propValueList[i].toString().toLowerCase().indexOf(searchKeyword) > -1)
            {
              filteredList.push(item);
              break;
            }
          }
        }
      });
    }
    return filteredList;
  }
}

//Usage

//<tr *ngFor="let company of companyList | filter: searchKeyword"></tr>

N'oubliez pas d'importer le tube dans le module de l'application

Il se peut que nous devions personnaliser la logique du déposant avec des dates.

alchi baucha
la source