Jany
Jany

Reputation: 57

How to use dynamic filters in Angular?

i'm trying to understand the logic behind using filters in Angular but im finding hard to configure it. I red about dynamic filters but i didn't understand how to use those. I hope you could give me some help.

I have a showcaseComponent where i wish to add three filters (Name, Description, Category) as text-type.

I type something like "Hello" in the Name filter and it shows me all the elements with "Hello" in the name for example.

I didn't find a proper guide that explain me step-by-step how to implement filters.

Upvotes: 0

Views: 1115

Answers (1)

Eliseo
Eliseo

Reputation: 57919

Jany. Angular works on observables, so a good approach are always observables. You can think in an observable as a function that return an object or an array in "async mode" (you don't get it also when you subscribe to it)

If you have three "inputs", we began create a FormGroup using ReactiveForms with this

form=new FormGroup({
  name:new FormControl(''),
  description:new FormControl(''),
  category:new FormControl(''),
})

A formGroup have a property that it's an Observable: valueChanges.

Now depend from your data and what are you using. If you use a simple array you can return an observable in this way

myWholeArray=[{...},{....},{...},...]
myArrayObservable$=this.form.valueChanges.pipe(
    startWith({name:'',description:'',category:''}),
    switchMap(res:any)>={
     //here you have an object of type {name:...,description:...,category:...}

     //if we have no input any value
     if (!res.name && !res.description && !res.catagory)
        return of(this.myWholeArray)
     
     //else you filter your array
     return of(
         this.myWholeArray.filter((x:any)=>{
             bool fulfilled=(res.name && x.name.toUpperCase().indexOf(res.name.toUpperCase())
             fulfilled=fullfilled && (res.description && x.description .toUpperCase().indexOf(res.description .toUpperCase())
             fulfilled=fulfilled && (res.category&& x.category.toUpperCase().indexOf(res.category.toUpperCase())

             return fullfilled;

         })
     )
}))

As you have an observable you indicate in the .html some like

<div *ngFor="let item of myArrayObservable$|async>
   {{item.name}} {{item.description}} {{item.category}}
</div>

Yes, I know I was too much quickly. So step by step

  • When we have an observable we can makes some operations over it. This "operations" are the rxjs/operators. This operators get one (or several) observable and transform in another one and we use using pipeand the operators separated by commas, like

       observable.pipe(firstOperator(res),secondOperator(res),...)
    
  • The first operator is startWith. One observable only show the value is you subscribe to it. Yo can subscribe explicitaly (by code using subscribe) or using the async pipe. As we want use this observable, we "initialize" giving an initial value.

  • The second operator is switchMap. switchMap transform one observable in another. So we transform the "valueChanges" in another observable. We need import this two operators import {startWith,switchMap} from 'rxjs/operators'

  • See that we need return an observable, so it's not valid return an array. To return an observable when we have an object or an array we use the third operator of (as is an creation operator, we need import {of} from 'rxjs')

Well. If you're using material and MatTableDataSource, the "property" filter makes the most part of work form you. See, e.g. this SO

You create the form and subscribe to valuesChanges

this.form.valueChanges.subscribe((res) => {
  this.dataSource.filter = JSON.stringify(res);
});

And create a custom function

Upvotes: 1

Related Questions