1

I have the below data object:

goods = [
    { name: 'Canon', title: 'Canon EOS 5D Mark III Body', tags: ['tag1','tag2','tag3']},
    { name: 'Nikon', title: 'Nikon D3100', tags: ['tag1','tag4','tag5']},
    { name: 'Sony', title: 'Sony CX700', tags: ['tag2','tag3','tag6']},
    { name: 'Fujifilm', title: 'Fujifilm XT20',tags: ['tag1','tag4','tag5']},       
  { name: 'Sony', title: 'Sony CX500', tags: ['tag3','tag4','tag5']},
  { name: 'Nikon', title: 'Nikon D750', tags: ['tag1','tag5','tag6']},
];

And a html page with 2 select boxes.

<select [(ngModel)]="selectedTag1" (change)="valueSelected1()">
 <option  *ngFor="let item of tagName">{{ item }}</option>
</select>

<select [(ngModel)]="selectedTag2" (change)="valueSelected2()">
 <option  *ngFor="let item of tagName">{{ item }}</option>
</select>

<div *ngFor="let item of goods">
 <app-goods [goodsData]="item"></app-goods>
</div>

In my ts file I would like to filter the tags array for selectedTag1, selectedTag2 or Both. i am not sure how to filter the array (do I need to loop through it?) AND I do not know how to combine the 2 filters (do I need combineLatest from RXJS?). I have the below so far

  ngOnInit() {
   this.tagName = this.dropdownService.brandName;
   this.goods = this.goodsService.goods;
  };

  public valueSelected1() {
   this.goods = this.goodsService.goods.filter(item => item.tags[0] === this.selectedTag1);
   console.log(this.selectedTag1);
  }
  public valueSelected2() {
   this.goods = this.goodsService.goods.filter(item => item.tags[0] === this.selectedTag1);
   console.log(this.selectedTag2);
  }

I think I need to loop through the array here item.tags[0] but not sure of the best way to do it and then do a combineLatest.. Maybe not? I have created a stackBlitz

2
  • Changed stackBlitz link as it was wrong. Commented Mar 2, 2020 at 12:37
  • do I need combineLatest from RXJS...no, you aren't doing anything with streams Commented Mar 2, 2020 at 12:48

3 Answers 3

2

You can do this in one of many number of ways:

  1. With a getter
get goodsFiltered(): any[] {
   return this.goods?.filter(({ tags }) => tags.indexOf(this.selectedTag1) !== -1 && tags.indexOf(this.selectedTag2) !== -1) ?? [];
}
  1. With a custom pipe (the best way imho)
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'filteredGoods' })
export class FilteredGoodsPipe implements PipeTransform {
  transform(goods: any[], { tag1, tag2 }): any[] {
    return goods.filter(({ tags }) => tags.indexOf(tag1) !== -1 && tags.indexOf(tag2) !== -1);
  }
}
<div *ngFor="let item of goods | filteredGoods: { tag1: selectedTag1, tag2: selectedTag2 }">
 <app-goods [goodsData]="item"></app-goods>
</div>
  1. Directly in your change event callbacks:
  public valueSelected1() {
   this.goods = this.goods.filter(({ tags }) => tags.indexOf(this.selectedTag1) !== -1 && tags.indexOf(this.selectedTag2) !== -1);
  }
  public valueSelected2() {
   this.goods = this.goods.filter(({ tags }) => tags.indexOf(this.selectedTag1) !== -1 && tags.indexOf(this.selectedTag2) !== -1);
  }

Hope this helps :)

Edit: I can't tell what types things have, but if this.goodsService.goods is an Observable, you should pipe the filter operator:

ngOnInit() {
   this.tagName = this.dropdownService.brandName;
   this.goods = this.goodsService.goods.pipe(
      filter(({ tags }) => tags.indexOf(this.selectedTag1) !== -1 && tags.indexOf(this.selectedTag2) !== -1)
   );
  }
Sign up to request clarification or add additional context in comments.

1 Comment

Great! Thanks for all your efforts with this, you have covered everything I could need. Top Answer!
2

You can use some method to check whether array contains some values:

public valueSelected1() {
    this.goods = this.goodsService.goods.filter(item => 
        item.tags.some(s => s == this.selectedTag1));
    console.log(this.selectedTag1);
}

public valueSelected2() {
    this.goods = this.goodsService.goods.filter(item => 
         item.tags.some( s => s == this.selectedTag1));
    console.log(this.selectedTag2);
}

Please, see a workstackblitz example.

Comments

1

Use below method instead of valueSelected1 and valueSelected2

 public onChangeSelection() {
      this.goods = this.goodsService.goods.filter(item => 
      (this.selectedTag1 && item.tags.includes(this.selectedTag1)) || 
       (this.selectedTag1 && item.tags.includes(this.selectedTag1)));

       console.log(this.selectedTag1);
 }

I used the includes syntax due to check the selectedTag exist in the array and which you checking the first index of the array, I think it's wrong

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.