Saturday, June 1, 2024
 Popular · Latest · Hot · Upcoming
178
rated 0 times [  181] [ 3]  / answers: 1 / hits: 6485  / 4 Years ago, mon, november 30, 2020, 12:00:00

I need to filter the table data according to the value I set in the input on keyup event. As there are multiple columns, filtered data should be displayed accordingly.


In my html I have below


             <tr>
<td *ngFor="let t of tableHeader">
<input type="text" [id]="t.key" (keyup)="inputChange($event)">
</td>
</tr>

My TS file is as below


    public inputChange(value) {
var prevData = this.dataSource;

if (this.selectedId == '') {
prevData = this.result;
}
else if (this.selectedId != '' && this.selectedId != value.target.id) {
prevData = this.result;
}

if (this.selectedId != '' && filterValue.target.value == '') {
this.result = prevData;
return;
}

this.selectedId = value.target.id;
this.inputValue = value.target.value;

var filteredData = this.result.filter(x => x[this.selectedId] && x[this.selectedId].toString().toLowerCase().includes(this.inputValue.toLowerCase()));
this.result = filteredData;
}

So far I have done this and get data filtered accordingly, but when I remove a value from a particular filter input, it loads the data source.


Expected: to display the previously filtered data instead of the data source.


More From » angular

 Answers
7

To achieve this I would use below steps using rxjs



  1. Define the datasource as an Observable


dataSource = [
{
firstname: "James",
lastname: "Amstrong",
othernames: "Angel",
age: 35
},
{
firstname: "John",
lastname: "Peter",
othernames: "Ava",
age: 43
},
...
]

We will convert this datasource to an observable using of from 'rxjs'



  1. Define the filter as an Observable


   tableHeader = [
{
key: "firstname"
},
{
key: "lastname"
},
...
];
filterKeyValues = this.tableHeader.map(({ key }) => ({ key, value: "" }));
filterSubject$ = new BehaviorSubject(this.filterKeyValues)
filter$ = this.filterSubject$.asObservable()

This simply generates an Observable with the structure


Observable<[{ key: firtname, value: ''}, { key: lastname, value: ''}, ...]>


  1. Combine the two and return a new Observable as the new filtered data


dataSource$ = combineLatest([
this.filter$, of(this.dataSource)
]).pipe(
map(([filter, dataSource]) =>
dataSource.filter(item =>
filter.every((value) =>
(new RegExp(String(value.value).toLowerCase())).test(String(item[value.key]).toLowerCase())

)
)
)
)


  1. Define handler for the inputChange


  public inputChange(event: any, key) {
this.filterKeyValues.find(({key: testKey}) => testKey === key).value = event.target.value
this.filterSubject$.next(this.filterKeyValues)
}


  1. Use async to display the contents


<table>
<tr>
<td *ngFor="let t of tableHeader">
<input type="text" [id]="t.key" (keyup)="inputChange($event, t.key)">
</td>
</tr>
<tr *ngFor="let item of dataSource$ | async">
<td>{{ item.firstname }}</td>
<td>{{ item.lastname }}</td>
<td>{{ item.othernames }}</td>
<td>{{ item.age }}</td>
</tr>
</table>

We are calling the next value. this will force a change detection and datasorce$ Observable will be reevaluated causing an update in the UI


I have made a Demo Here to illustrate this approach


[#2203] Wednesday, November 25, 2020, 4 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
sonja

Total Points: 541
Total Questions: 113
Total Answers: 114

Location: Anguilla
Member since Sun, Jan 29, 2023
1 Year ago
sonja questions
Sun, Oct 11, 20, 00:00, 4 Years ago
Thu, May 21, 20, 00:00, 4 Years ago
Sun, Nov 10, 19, 00:00, 5 Years ago
Mon, Aug 26, 19, 00:00, 5 Years ago
;