2017-09-27 4 views
0

Une vue la liste des entrées en utilisant un * ngFor basées sur une Observable:* ngPour les itérations d'un observable. Filtrage onInput devrait être possible. Comment?

view.html

<ion-searchbar [(ngModel)]="filter" (ionInput)="filterMeds()"></ion-searchbar> 
<ion-list> 
    <ion-item *ngFor="let medicine of getMeds$() | async"> 
     {{medicine.name}} 
    </ion-item> 
</ion-list> 

La composante relaie juste une fonction observable par les getMeds $():

component.ts

private _refreshOnInput$: Subject<any> = new Subject(); 


getMeds$(){ 
    return this.medsService.medsArray$; 
} 

Th Le service lui-même renvoie simplement le tableau comme un observable: Observable<Medicine[]>

La médecine est un objet simple constitué de quelques chaînes de chiffres.

Maintenant, ma question: view.html ajoute une barre de recherche. Chaque fois que les utilisateurs modifie les critères de recherche, la fonction filterMeds() est appelée:

filterMeds(){ 
    this._refreshOnInput$.next(true); 
} 

Ce qui suit un blog post (cmd-f le texte « bouton refresh » pour voir ce que je suis en train de mettre en œuvre).

Je comprends que mon * ngFor doit itérer sur un observable qui fusionne à la fois l'original this.medsService.medsArray$ et le _refreshOnInput() après avoir appliqué un certain filtrage.

component.ts ** ** tentent

filteredMeds$: Observable<Medicine[]> 

// Constructor 

// An event is fired whenever the search input's updated 
filteredMeds$ = this._refreshOnInput$.map(() => 
    this.medsService.medsArray$ 
    .map(meds => 
     meds.filter(med => 
     med.name.toLowerCase().indexOf(this.filter.toLowerCase()) > -1 
    ) 
    ) 
); 

this.meds$ = Observable.merge(this.medsService.medsArray$, filteredMeds$); 

// Updating the getMeds$() method: 
getMeds$(){ 
    return this.medsService.medsArray$; 
} 

Je ne peux pas comprendre comment créer un flux filtré valide. La même erreur se produit lorsque je sers directement la filteredMeds $ observable * ngFor:

ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed 

Répondre

0

Peut-être que ce n'est pas la meilleure solution MAIS cela fonctionne. Donc, s'il vous plaît commenter sur cette approche:

private _refreshMeds: Subject<any> = new Subject(); 
    meds$: Observable<any>; 
    filter: string = ''; 

    constructor(@Inject(MedsService) private medsService: MedsService) { 

    let filtered$ = new Observable(obs => { 
     this._refreshMeds.subscribe(() => 
     this.medsService.medsArray$.first().subscribe(medsArray => { 

      const filteredMeds = medsArray.filter(med => 
      (this.filter.length === 0) || 
      (med.name.toLowerCase().indexOf(this.filter.toLowerCase()) > -1)); 
      obs.next(filteredMeds); 
     }) 
    ) 
    }); 

    // Merging both the unfiltered (ie. at page load) or the filtered version 
    this.meds$ = Observable.merge(this.medsService.medsArray$, filtered$); 
    } 

    // Called by the input's changed listener (ionic: ionInput) 
    filterMeds(){ 
    this._refreshMeds.next(true); 
    } 
1

Je suppose que vous devez itérer par (getMeds$() | async) ainsi:

<ion-item *ngFor="let medicine of (getMeds$() | async)"> 

parce que dans votre exemple, vous utilisez async tuyau sur médecine objet, aucun résultat de getMeds $ méthode.


Mais mieux est d'utiliser publique référence à medsService (dans le composant) et votre boucle ngFor devrait ressembler à ce que:

<ion-item *ngFor="let medicine of (medsService.medsArray$ | async)"> 

parce que vous ne devriez pas utiliser la méthode en html (comme argument de la boucle ngFor ou de la condition ngIf). Chaque changement de vue sera appelé méthode getMeds $() dans votre cas, ce qui est complètement inutile pour Observables.

+0

Salut Jaroslaw, merci pour l'entrée, mais j'ai oublié de mentionner que l'observable non filtré de base affiche correctement. Le problème vient de mon filtrage. Mais merci pour le conseil de la meilleure pratique! – Jem