25

I have a primeng turbo-table component. I need to apply multiple filters on the table.
From the parent I call
myTable.doFilter(first_values); myTable.doFilter(second_values); one after the other

On the child (turbo-table) component, the actual filter is applied like
doFilter(...filter_values...){ this.pTable.filter(...filter_values...); } The problem is that the second filter is applied before the first is finished and is causing unexpected results.
How can I call the filters once the previous filter is finished. An event is emitted once a filter is completed but I cant find a way to leverage it.

Parent.ts

     fetchList(searchData) {
            this.ratesTable.reset();
            this.ratesDataSource = [];
            this.programService.fetchList(searchData)
              .then(
                (response) => {
        
                  this.ratesDataSource = response.rates;
                  this.doTermFilter();
                  this.doLoanFilter();
                })
              .catch((error) => {
                console.error("from ts" + error);
              });
          }
        doTermFilter(){
        this.doFilter({ filterValue: _termFilters, columnField: "COL1", filterMethod: "in" });
        }
    doLoanFilter(){
        this.doFilter({ filterValue: _loanFilters, columnField: "COL7", filterMethod: "in" });
        }

child.ts(turbo-table)

     doFilter(doFilterInput: { filterValue: any[], columnField: any, filterMethod: any }) {
        this.pTable.filter(doFilterInput.filterValue, doFilterInput.columnField, doFilterInput.filterMethod);
        }

Any help is much appreciated. Thanks

Owen Kelvin
  • 14,054
  • 10
  • 41
  • 74
Abdu Manas C A
  • 1,089
  • 1
  • 11
  • 19
  • 1
    Have you tried to put the second filter inside a timeout? – Osakr Jul 24 '18 at 10:03
  • Yes, but the problem is that, the total number of rows in the table may vary. From 1 to even thousands. It will work with the timeout, but I dont think thats such a clean code. – Abdu Manas C A Jul 24 '18 at 10:41
  • Well, timeouts are very useful for setting a function to the end of the callstack so It might work. Obviously is not the best way to do it, the best would be overriding the method creating your custom p-table. An other way to do it is playing with promises, timeouts and recursive functions – Osakr Jul 24 '18 at 10:54
  • Are you sure you want to filter or sort, if you are filtering what is in first level second level. https://www.primefaces.org/primeng/#/table – Nithila Shanmugananthan Oct 18 '18 at 08:27

6 Answers6

1

you can use async/await as :

    fetchList(searchData) {
        this.ratesTable.reset();
        this.ratesDataSource = [];
        this.programService.fetchList(searchData)
          .then(
            (response) => {
    
              this.ratesDataSource = response.rates;
              await this.doTermFilter();
              await this.doLoanFilter();
            })
          .catch((error) => {
            console.error("from ts" + error);
          });
    }
    async doTermFilter(){
        this.doFilter({ filterValue: _termFilters, columnField: "COL1", filterMethod: "in" });
    }
    async doLoanFilter(){
        this.doFilter({ filterValue: _loanFilters, columnField: "COL7", filterMethod: "in" });
    }
Amir BenAmara
  • 676
  • 7
  • 12
0

This is filter method source code:

filter(value, field, matchMode) {
    if(this.filterTimeout) {
        clearTimeout(this.filterTimeout);
    }

    if (!this.isFilterBlank(value)) {
        this.filters[field] = { value: value, matchMode: matchMode };
    } else if (this.filters[field]) {
        delete this.filters[field];
    }

    this.filterTimeout = setTimeout(() => {
        this._filter();
        this.filterTimeout = null;
    }, this.filterDelay);
}

You can see they are using timeouts and event is emitted only once, because previous timeout gets canceled, but overall situation is not clear without full example.

Link: https://github.com/primefaces/primeng/blob/master/src/app/components/table/table.ts

kemsky
  • 14,727
  • 3
  • 32
  • 51
  • hi..the filter code is handled by primeng itself. By just calling the `this.pTable.filter(...filter_values...);` the table is filtered (pTable is the local idenitifier given to primeng table ) . Once the filtering finishes, an event is emitted . But i was not able to leverage it. Let me try your approach. – Abdu Manas C A Jul 24 '18 at 05:06
0

Check out my answer to How to filter complex structured Json data in Angular 6 - I use the rxjs Observable pattern to implement a reactive/functional/declarative solution to filtering a table that I think matches your use case...? (it's difficult to tell without code)

ZackDeRose
  • 2,146
  • 1
  • 16
  • 28
0

I do not know how your table's event system work, but in general, you shall be able to do something like this:

myTable.pTableReference.onFilterEvent(someData => myTable.doFilter(second_values));
myTable.doFilter(first_values);

You can also try to promisify your event-driven approach:

// child

doFilter(values): Promise<any> {
  return new Promise<any>((resolve, reject) =>
    this.pTable.onFilterEvent(resolve);
    try {
      this.pTable.filter(values);
    }
    catch(e) {
      reject(e);
    }
  )
}

// parent

myFilterFunction() {
  myTable.doFilter(first_values).then(result => myTable.doFilter(second_data));
}

// or using the `await` keyword
async myFilterFunction() {
  await myTable.doFilter(first_values);
  await myTable.doFilter(second_data);
}

Or go even further and make it into Observables.

As I said in the beginning, it all depends on how your event system works and on how you register callbacks for them...

Hope this helps a little :-)

Heehaaw
  • 2,677
  • 17
  • 27
0

There’s a special syntax to work with asynchronous functions in Javascript, called async/await. It’s surprisingly easy to understand and use. In your case:

async applyFilters() {
  await this.doTermFilter();
  this.doLoanFilter();
}

The keyword await will make JavaScript wait until doTermFilter() settles and then call the doLoanFilter().

fetchList(searchData) {
...
this.ratesDataSource = response.rates;
this.applyFilters();

Async Function

Await

Abdul Rafay
  • 3,241
  • 4
  • 25
  • 50
0

You can create an event emitter in child component and emit value to parent component once filter operation gets completed.

Parent Component html:

<childComponent (filterEventEmitter)='handleFilterEvent($event)'></childComponent>

Parent Component .ts file:

handleFilterEvent(data) {
   if(data.filterType === 'termFilter') {
       this.doLoanFilter();
   }
}
    
fetchList(searchData) {
   this.ratesTable.reset();
   this.ratesDataSource = [];
   this.programService.fetchList(searchData)
        .then(
              (response) => {
            
                  this.ratesDataSource = response.rates;
                  this.doTermFilter();
        })
        .catch((error) => {
             console.error("from ts" + error);
        });
}

Child component:

@Output filterEventEmitter : EventEmitter = new EventEmitter(null);
doFilter(args) {
    // filter operations
    filterEventEmitter.emit({filterType: 'TermFilter'});
}
Dmitry S.
  • 1,544
  • 2
  • 13
  • 22