1
votes

I am new to ionic, following some tutorials and trying to learn and apply other stuff. I think what I'm trying to achieve is quite simple, but I can't seem to have it working.

What I'm trying to do is simply to filter results using the ion-select element to display its correspondent pick from the select.

So what I have is this ion-select where I'm using the ngModel and ngFor to filter which options the user should have, and once the user select their option, the app should only display the correspondent results, in this case, a Sport (so if the user picks 'Soccer' in the ion-select, only the 'Soccer' ion-cards should be displayed, I have those connected in the back end.

I'm adding here a piece of the code, but I'm afraid you might need other piece of code to get it more clear, so let me know please. Cheers guys!

<ion-content padding>

<ion-item>
  <ion-label>Filter by Sport</ion-label>
  <ion-select [(ngModel)]="list" multiple="true">
    <ion-option *ngFor="let item of list">{{item.sport}}</ion-option>
  </ion-select>
</ion-item>

    <ion-card *ngFor="let item of list">    
      <ion-card-content>
        <ion-card-title>{{item.title}}</ion-card-title>
        <p>Sport: {{item.sport}}</p>
        <p>Participants: {{item.players}}</p>
        <p>When: {{item.when}}</p>
        <p>{{item.description}}</p>
        <p>Location: {{item.location}}</p>
        <button ion-button block (click)="joinEvent(item)">Join!</button>
      </ion-card-content>
    </ion-card>

</ion-content>

Edit: Added .ts code below:

export class JoinEventPage {

  filterListBy$
  filteredList$

    list: IEvent[];
  joined = [];

  constructor(public navCtrl: NavController, 
              public navParams: NavParams, 
              public eventProvider: EventsProvider,
          public joinedEventsProvider: JoinedEventsProvider) {

  }

  ionViewDidEnter(){

    // create observable
    this.filterListBy$ = Observable.from(this.list)
      // pull out just the name of the sport
      .map((a: any) => a.sport)
      // make sure items are distinct
      .distinct()
      // return an array
      .toArray();

    // force the initial filtering of the list
    this.changeCategory([])

    // this.eventProvider.listEvents().subscribe(res=>{
    //  this.list = res;
    // }, error => {
    //  console.log("Error: " + error.message);
    // });

    // this.joinedEventsProvider.getStorage('joined-events').then(res => {
    //   if(res){
    //     this.joined = res;
    //   }
    // });
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad JoinEventPage');
  }

  joinEvent(item){
    for(let event of this.joined){
      if(event.id == item.id){
        console.log("You already joined this event!")
        return;
      }
    }
    this.joined.push(item);
    this.joinedEventsProvider.setStorage('joined-events', this.joined);
  }

  changeCategory(_value) {
    // if nothing selected, show all
    if (!_value.length) {
      return this.filteredList$ = Observable.from(this.list).toArray();
    }

    // if something selected, filter the list based on the item selected which 
    // will be in the array parameter "_value"
    this.filteredList$ = Observable.from(this.list)
      .filter((i) => { return _value.indexOf(i.sport) !== -1 })
      .toArray()
  }

}

Solution: The only change I did to the .ts file following Aaron's solution is below:

ionViewDidEnter(){

    this.eventProvider.listEvents().subscribe(res=>{
    this.list = res; 

     // create observable
    this.filterListBy$ = Observable.from(this.list)
      // pull out just the name of the sport
      .map((a: any) => a.sport)
      // make sure items are distinct
      .distinct()
      // return an array
      .toArray();

    // force the initial filtering of the list
    this.changeCategory([])

    this.joinedEventsProvider.getStorage('joined-events').then(res => {
        if(res){
          this.joined = res;
        }
      });

    });


  }
1
Change [(ngModel)]="list" with [(ngModel)]="selectedList" and create global variable for name selectedList. And your ion-option tag hasn't [value] attribute. Plese add this attribute your ion-option tag. For ex: [value]='item.sport'. - Omsl
@Omsl thanks, I'm trying to work out your idea, but no luck. Could you add your example to the code? I was thinking that the 'list' still needed to be there because it holds all the items that could be filtered, but I get your idea of having the selectedList to hold the ones that the user picked, I'm just not able to put them to work :( - DisplayName

1 Answers

1
votes

see full answer here, but highlights are below

https://stackblitz.com/edit/ionic-tkqzr6

  ngOnInit() {
    // create observable
    this.filterListBy$ = Observable.from(this.list)
      // pull out just the name of the sport
      .map((a: any) => a.sport)
      // make sure items are distinct
      .distinct()
      // return an array
      .toArray();

    // force the initial filtering of the list
    this.onChange([])
  }

when the user selects an option, we call onChange

  onChange(_value) {
    // if nothing selected, show all
    if (!_value.length) {
      return this.filteredList$ = Observable.from(this.list).toArray();
    }

    // if something selected, filter the list based on the item selected which 
    // will be in the array parameter "_value"
    this.filteredList$ = Observable.from(this.list)
      .filter((i) => { return _value.indexOf(i.sport) !== -1 })
      .toArray()
  }

now in the html

<ion-item>
    <ion-label>Filter by Sport</ion-label>
    <ion-select multiple="true" (ionChange)="onChange($event)">
        <ion-option *ngFor="let item of (filterListBy$ | async)">{{item}}</ion-option>
    </ion-select>
</ion-item>