Troy Bryant
Troy Bryant

Reputation: 1024

Angular2 auto complete filter *ngFor data

I am learning angular 2 pipes and running into problem. I have an auto complete box that once input selected should filter out the data from my *ngFor that displays a list of cards. Right now when you start typing the autocomplete works but when the actual category is selected the list of cards in the ngFor does not filter. What am I missing?

Thanks

So here is my auto complete :

<form class="example-form">
  <md-form-field class="example-full-width">
  <input type="text" placeholder="Select a sport" aria-label="Number" mdInput 
     [formControl]="myControl" [mdAutocomplete]="auto">
    <md-autocomplete #auto="mdAutocomplete">
    <md-option *ngFor="let option of filteredOptions | matchesSport:option | 
     async" [value]="option">
      {{ option }}
    </md-option>
  </md-autocomplete>
</md-form-field>
</form>

Here is my *ngFor displaying a list of md-cards:

  <md-list>      
  <md-list-item *ngFor="let g of games; let i = index | matchesSport:option" (click)="onSelect(g)" [class.active]="i == selectedRow">
    <md-card tabindex="-1">
      <md-card-content>
        <p md-line> {{g.Sport}}<span><i class="material-icons">accessibility</i></span> </p>
      </md-card-content>
      <md-card-actions>
        <button md-button md-raised-button>LIKE</button>
        <button md-button md-raised-button>SHARE</button>
      </md-card-actions>
    </md-card>
  </md-list-item>
</md-list>

And here is my pipe

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

@Pipe({
    name:'matchesSport'
})

 export class MatchesSportPipe implements PipeTransform {
    transform(items: any, category: string): Array<any> {            
    return items.filter(item => item.Sport === category);
  }
 }

And here is my controller :

import { Component, OnInit } from '@angular/core'; 
import { Game } from './models/game.model';
import { GameService } from './services/game-service';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs/Observable';     
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/map';

export class AppComponent implements OnInit {
  title = 'app';
  games: any[] = [ ];
  statusMessage: string = "Loading games...";
  selectedRow: Object;
  setClickedRow: Function;
  selectedGame: Game;
  myControl: FormControl = new FormControl();

  options = [
   'Football',
   'Basketball',
   'Baseball',
   'Lacrosse',
   'Volleyball'
  ];

   filteredOptions: Observable<string[]>;

   constructor(private _gameService: GameService) {
     this.filteredOptions = this.myControl.valueChanges
     .startWith(null)
     .map(val => val ? this.filter(val) : this.options.slice());
    }
   filter(val: string): string[] {
     return this.options.filter(option =>
     option.toLowerCase().indexOf(val.toLowerCase()) === 0);
   }

   onSelect(game: Game): void {
     this.selectedGame = game;
    }


   ngOnInit() {
        return this._gameService.getGames()
       .subscribe((gameData) => this.games = gameData,
       (error) => {
       this.statusMessage = " something broke"
     });

   }
 }

Upvotes: 0

Views: 3137

Answers (1)

Fetrarij
Fetrarij

Reputation: 7326

First, Index should be after the pipe:

<md-list-item *ngFor="let g of games | matchesSport:option; let i = index ">
  ...
</md-list-item>

And, you use option which is undefined in the pipe. You need to get the value choosed from the autocomplete and put this the pipe argument (here option):

You can use: optionSelected event in mat-autocomplete

<mat-autocomplete #auto="matAutocomplete" (optionSelected)="optionSelected($event)" name="myname">
  <mat-option *ngFor="let option of options" [value]="option">
...
  </mat-option>
</mat-autocomplete>

and in component:

option: string; // <-- use it now
// ...
optionSelected(e) {
  this.option = e.option.value;
}

Then, for the error:

error of : ERROR TypeError: Cannot read property 'filter' of undefined at MatchesSportPipe.webpackJsonp.../../../../../src/app/customP‌​ipe.ts.MatchesSportP‌​ipe.transform (customPipe.ts:9)

You now need to check in your pipe if items are undefined, if category is undefined, before filtering items.

export class MatchesSportPipe implements PipeTransform {
    transform(items: any[], category: string): Array<any> {  
    if (!items) return [];  
    if (!category) return items;        
    return items.filter(item => item.Sport === category);
  }

The whole behaviour resumed in a working plunker: https://embed.plnkr.co/4NDIy84YFW7OZkVPJZo5/

Upvotes: 1

Related Questions