Tabulator: Tabulator Ajax Header Filter not working properly

Created on 2 Apr 2019  路  41Comments  路  Source: olifolkerd/tabulator

Dear Team,

I have my tabulator table inside bootstrap modal. I have ajaxFiltering enabled in my table and I'm using header filter in each column to filter the data. I have set headerFilterLiveFilter to false. Now if I enter a value in input in the first column and tab or press enter ajax filter is happening and filtered data is returned.

I have a clear filter button. In this button click, I'm calling table.clearHeaderFilter() This clears the headerfilter and an ajax call is made and full data set is returned automatically.

Now if I again type value in the header filter input in the first column and if i press enter or tab out ajax filter is not working. Also tabbing out and navigating to next input triggers an ajax call. This happens even if I press tab to skip second column with an empty value.

Thanks,
Abdul

Bug

Most helpful comment

Thanks for the detailed investigation @aklaver it should be a quick fix, i will include it in the next patch release.

Cheers

Oli :)

All 41 comments

So this is a follow on to:
https://github.com/olifolkerd/tabulator/issues/1949

Tabulator version.
Also a simple example on CodePen or jsFiddle would help.

Hi @aklaver ,

I'm using Tabulator V4.2.3 I figured out what is making this wrong. But I don't know how to fix this. When I have values in the header filter input and if I press tab ajax filter request is triggered. If I remove the value in the same header input and press tab no ajax filter request is triggered. But after removing the search input text if I press enter key instead of tab, ajax filter request is made. This is completely fine. I guess Tabulator is programmed in this way to avoid making unnecessary ajax calls If just tab on empty header inputs for navigation purpose. This is fine and acceptable.

But lets say, I have some 10 columns and I have entered header filter text in some random columns, lets keep this to minimum say 1 column randomly. Now If I need to clear the filters in this column and reset the search. For this, I have added a button and on click of this button, I'm calling table.clearHeaderFilter() This clears the header filter and all rows are returned from the server. Now if I focus on first column search input and press tab to move to next header input, ajax call is triggered even if the header inputs are empty without any values. This happens for all columns with empty header filter inputs,

I manually went to the previous column where I had search value and added new search value and I pressed enter key in that column header input and now If I make search, search is working fine. ajax calls are not triggered unnecessarily on press of tab in empty header filter inputs.

How to fix this? Any workaround? Since I'm using ajaxFilter on server side, I'm unable to produce codepen or jsfiddle sample.

Thanks,
Abdul

Hi @aklaver ,

Right now as a work around, I'm destroying and recreating the table on click of reset search button.

Thanks,
Abdul

@fingers10 . Looking at code for clearHeaderFilter in modules/filter.js I see:`

`//clear header filters
Filter.prototype.clearHeaderFilter = function(){
var self = this;

    this.headerFilters = {};

    this.headerFilterColumns.forEach(function(column){
            column.modules.filter.value = null;
            self.reloadHeaderFilter(column);
    });

    this.changed = true;

};
`
Note the this.changed = true;

From here:

https://github.com/olifolkerd/tabulator/issues/1476
"Hey @aklaver

I have just pushed an update to the master branch to ensure that it is only fired again if the value of the header filter changes.

Cheers

Oli :)"

From what I can see the initial clearHeaderFilter marks the filters as changed and fires the filter code when you tab through. The next time around there is no change from previous value so they do not fire. Unfortunately at this point I cannot think of a solution. I will continue to think on this though.

Hey @aklaver

Thanks for the details,

I will look into fixing that in the next patch release.

Cheers

Oli :)

Hey @fingers10

Looking into this further i am unable to replicate what you describe. Setting up the table as you have described with ajaxFiltering enabled and headerFilterLiveFilter set to false the table works as expected

  • When a value is changed in a header filter and focus is lost on the editor a request is triggered
  • When a value is deleted from an editor a request is triggered
  • When the clearHeaderFilter is used the request is triggered
  • after clearHeaderFilter has been used the above functions work exactly as they did before.

Im afraid without having a working JS Fiddle or Code Pen it will be impossible for us to resolve your issue as there is currently no way to replicate it, we need to understand exactly how your table is configured.

Also could you let us know which browser you are using?

Cheers

Oli :)

Dear @olifolkerd ,

I'm still facing this issue. I'm using Tabulator Version 4.2.3 and I tested this in Edge and Chrome.

Steps to Reproduce:

  1. I have a Search Results Table(Tabulator Table) in a Page. This table is loaded via ajax and server side sorting enabled. There is no search filters in this table.
  2. On click of a cell in above table, a bootstrap modal dialog appears, in which I have another Tabulator Table. Again this table is also loaded via ajax. This has server side sorting and searching enabled.
  3. For this table inside bootstrap modal, enable header filters and configure header live filter to false for all columns.
  4. Now a make a search, server side search will happen and results will be returned.
  5. Now click on a reset filter button which will fire table.clearHeaderFilter() for this table.
  6. Now if you try to search again, the search functionality breaks.
  7. As a work around, I'm destroying the table on click of reset filter button and reinitialize the table again.

Thanks,
Abdul

@fingers10
The search does not break it just fires with empty values at least according to your original problem description.

@olifolkerd
The 'issue' from what I see is:
1) You have multiple header search fields.
2) You search on a subset of those fields by entering search values.
3) You run clearHeaderFilter(). This clears the fields and marks them as changed.
4) If you enter a field that had value in the previous search and is empty and marked as changed now as result of clearHeaderFilter() and then move out of it then an AJAX request is fired that includes that field(empty value) and all the other fields that had values in the previous search but are empty now. The fields that where empty in previous search are left out.

To me that seems to indicate that there maybe two change tracking mechanisms at work and that one is actually looking at what the previous value was and is using that to determine whether to include the current value in a search. When I get a chance I will see if I can figure a way to use CodePen to deal with an AJAX request. jsFiddle can work with a dummy AJAX request, but I do not see how to get that to respond to a filter request. CodePen allows accessing third party sites, just have to figure out how to get that to work. On that note, would it be possible to set up an AJAX test data site on tabulator.info?

@aklaver Thanks for clarifying

It is just that the filters have gone from having a value of undefined to a value of "" which are treated different for internal filtering but i see how that could be confusing for ajax.

I will look into tweaking this for the next patch release.

Cheers

Oli :)

Dear @olifolkerd ,

Any updates on the next patch release with this fix?

Thanks,
Abdul

hey abdul,

i have stuck this on the roadmap for investigation for the 4.3 release in may

Cheers

Oli :)

Dear olifolkerd,

I'm pretty sure your about to release 4.3 soon. Please don't forget to add a fix for this issue. I keep watching and I'll test once the 4.3 is released and update you.

Thanks,
Abdul

Dear olifolkerd.

Here is the demo gif explaining the above bug. If the gif is not displayed, then please click on it to view.

Tabulator Ajax Header Filter Bug

Here are the observations from demo gif. All the below observations can be seen in the console log in the same gif.

  1. I'm entering name in FirstName search input and on pressing enter search is triggered. - Correct Behavior.

  2. I press Tab key and enter name in LastName search input and on pressing enter search is triggered. - Correct Behavior.

  3. I remove the last name from the LastName search input and I'm not pressing enter instead I press Tab key and enter designation in Designation search input and on pressing enter search is triggered. - As I highlighted in the console, even though the LastName search input is empty in table ui Tabulator picks the previous value in that column and passes it to server. This is because I didn't press enter in the previous step after clearing the search input. - Incorrect Behavior and Bug.

  4. Now I'm pressing the Reset Search Button which in turn calls userGrid.clearHeaderFilter(); and now If I press Tab key from first column till last column, you can see the Ajax Search getting triggered for each column. - Bug.

This is the issue I'm explaining in this thread. Step 3 and 4 needs to be fixed for this issue.

Please revert for any further clarifications.

P.S. I'm using Tabulator v-4.2.7.

Thanks,
Abdul (A Tabulator Fan)

Dear Olifolkerd,

Thanks for the note on update release. Don't worry on your family situation. Things will go in a good way as expected. I pray and wish your family to get well soon.

Also I have created a repo called Tabular Bugs to save the gif or video explaining the bugs. I have also added a gif link for this bug in the previous comment. Please review the gif image in the link and I'll keep testing and using Tabulator and if I find something I'll post.

Cheers,
Abdul (Proud Tabulator Fan)

Hi Olifolkerd,

Did you get a chance to look at the third point in the above comment? I think that behavior needs to be corrected.

Please can you share your views on this?

Thanks,
Abdul

Hey @olifolkerd ,

I checked the v4.3.0 release notes. This issue not addressed?

Thanks,
Abdul

Hey @fingers10

As per issue #2213 i got as many updates in as i could for this release, but i have not had time to address them all, i prioritised those that affected users the most or were quick to get in.

I understand that this issue is clearly important to you, but this continual messaging to check on my progress really must stop, i will drop a message on this issue as soon as i have a chance to look at it, I will tackle problems when i get time and in the order that appears most urgent to me (remember i do all this for FREE).

If you wish to have results sooner then i would welcome a pull request with a fix for the issue.

Tabulator has 1000's of users and it is unrealistic to expect me to be able to provide personal feedback on every issues progress constantly, especially as you seem keen to not only try and message me on here but through Linked In to check on my progress!

I will always respond to issues, but only when i have something new to say, if i had to reply to every single Tabulator user with updates on every question and update i would be working 24 hours a day just to keep up.

Please respect the fact that i have a life outside of Tabulator and will respond when i have something new to add.

I really do appreciate your eagerness and involvement in Tabulator, but please just be a bit more realistic about your expectations of my ability to personally respond to everything.

Cheers

Oli :)

Hi @olifolkerd ,

I'm sorry. The intent was to make Tabulator awesome and not to disturb or track you. The day I started using Tabulator, I really liked this. I was just curious of updates and I thought ajax sourced data will be used by many and so thought this as a major issue.

Anyways, I respect your works and response. Many thanks and I'll be with in limits and i'll wait.

Apologies again.

Thanks,
Abdul

Hey @fingers10

You will be happy to hear i have pushed a fix for this to the 4.4 branch which will be released later today.

Cheers

Oli :)

Hey @olifolkerd,

Sounds great to hear. Thanks for the awesome work. Looking forward for the release.

Thanks,
Abdul

Dear @olifolkerd ,

I tested this with v4.4.0. Issue still exists. as per my previous comments the below two issue still exists.

  1. I remove the last name from the LastName search input and I'm not pressing enter instead I press Tab key and enter designation in Designation search input and on pressing enter search is triggered. - As I highlighted in the console, even though the LastName search input is empty in table ui Tabulator picks the previous value in that column and passes it to server. This is because I didn't press enter in the previous step after clearing the search input. - Incorrect Behavior and Bug.

  2. Now I'm pressing the Reset Search Button which in turn calls userGrid.clearHeaderFilter(); and now If I press Tab key from first column till last column, you can see the Ajax Search getting triggered for each column with empty array. - Bug.

Thanks,
Abdul

Are u sure u flushed your cache as I'm not seeing that any more

Are u sure u flushed your cache as I'm not seeing that any more

Yep I too have cache busting enabled and I took the files from master branch dist folder

I tested again and verified the issue happening again with v4.4.0

Can you provide the table constructor, filter code?

@aklaver , Here is my table setup,

var userGrid = new window.Tabulator("#tableUserResults",
                {
                    placeholder: "No Data Available",
                    layout: "fitColumns",
                    height: height + 27,
                    selectable: false,
                    ajaxURL: window.userUrls.getAll,
                    ajaxConfig: {
                        global: false,
                        async: true
                    },
                    ajaxSorting: true,
                    ajaxFiltering: true,
                    ajaxURLGenerator: function (url, config, params) {
                        const sorters = params.sorters || [];
                        delete params.sorters;
                        sortUrl = sorters.map(sort => `orderby=${sort.field.toLowerCase()} ${sort.dir}`).join('&');

                        const filters = params.filters || [];
                        delete params.filters;

                        const operators = {
                            '=': 'eq',
                            '>': 'gt',
                            '>=': 'gte',
                            '<': 'lt',
                            '<=': 'lte',
                            '!=': 'neq',
                            like: 'co'
                        };

                        (filters || []).forEach((filter) => {
                            filter.type = operators[filter.type] || filter.type;
                        });
                        searchUrl = filters.map(filter => `search=${filter.field.toLowerCase()} ${filter.type} ${filter.value}`).join('&');

                        return `${url}?${sortUrl}&${searchUrl}`;
                    },
                    ajaxResponse: function (url, params, response) {
                        return response.Items;
                    },
                    renderComplete: function () {
                        const count = userGrid.getDataCount();

                        $('#btnSearchResultsExportToExcel').prop('disabled', !(count > 0));
                        $('#spanResultsCount').text(count);
                        $('section.card').height(height + 27);
                    },
                    tooltipsHeader: true,
                    tooltips: true,
                    virtualDomBuffer: height + 27,
                    initialSort: [
                        {
                            column: 'FirstName',
                            dir: 'asc'
                        }
                    ],
                    columns: [
                        {
                            formatter: "rowSelection",
                            titleFormatter: "rowSelection",
                            align: "center",
                            headerSort: false,
                            width: 50,
                            headerSort: false,
                            headerFilter: false,
                            cssClass: 'text-center',
                            frozen: true,
                            headerTooltip: false,
                            tooltip: false,
                            resizable: false,
                            cellClick: function (e, cell) {
                                cell.getRow().toggleSelect();
                            }
                        },
                        {
                            title: 'First Name',
                            field: 'FirstName',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search First Name',
                            formatter: function (cell, formatterParams, onRendered) {
                                return '<a href="#" class="text-underline" aria-haspopup="true">' + cell.getValue() + '</a>';
                            },
                            cellClick: function (e, cell) {
                                $.when(ajaxGetAsync(window.userUrls.getById, { id: cell.getData().Id }, true, window.htmlDataType)).done((response) => {
                                    document.querySelector('#userEntryPartial').innerHTML = response;
                                    $('#userEditModal').modal('show');

                                    userEditForm = $('#formUserEdit').serialize();
                                });
                            }
                        },
                        {
                            title: 'Last Name',
                            field: 'LastName',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search Last Name'
                        },
                        {
                            title: 'Designation',
                            field: 'Designation',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search Designation'
                        },
                        {
                            title: 'Identity Number',
                            field: 'IdentityNumber',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search Identity Number'
                        },
                        {
                            title: 'Brand Name',
                            field: 'Profile.BrandName',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search Brand Name'
                        },
                        {
                            title: 'Client Name',
                            field: 'Profile.Client.Name',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search Client Name'
                        },
                        {
                            title: 'Contact Email',
                            field: 'Profile.ProfileContact.Email',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search Contact Email'
                        },
                        {
                            title: 'Business Name',
                            field: 'Profile.Client.Business.Name',
                            headerFilter: 'input',
                            headerFilterLiveFilter: false,
                            headerFilterPlaceholder: 'Search Business Name'
                        },
                        {
                            title: 'User ID',
                            field: 'Id',
                            visible: false,
                            headerFilter: false,
                            headerSort: false,
                            tooltip: false,
                            resizable: false
                        }
                    ]
                });

By any chance this issue #1949 related code or logics is getting reset on calling userGrid.clearHeaderFilter()?

I will take a look at this as I get time.

Narrowed it down. In filters.js the code is not getting to:

91                                 delete self.headerFilters[field];

when the filter is blanked. So the filters stay around when they should not. More investigation needed to see why the above line is not reached.

@aklaver great work. Thanks for finding out.

Further down the rabbit hole. Seems it is keyed to headerFilterLiveFilter: false. If this is set to true then you do not see the above behavior. In filters.js:

if(column.definition.headerFilterLiveFilter !== false){
...

There is no else to deal with the false case, so all the code in the if (){} is skipped. @olifolkerd will need to comment on whether that is intended or not. Alright I see what is going on. If headerFilterLiveFilter is true then the searchTrigger is called and in there the success() is called. success() is where delete self.headerFilters[field] is used. So in the headerFilterLiveFilter: false case success() is never called on the input editor and the filter is not cleared. Now it comes down to figuring out the best way to handle this.

Thanks for the detailed investigation @aklaver it should be a quick fix, i will include it in the next patch release.

Cheers

Oli :)

@olifolkerd I'm really afraid to ask. Please can you change type from question to bug? So that it will be easy to track.

No problem, i generally leave things marked as questions until it has been confirmed as a bug (a lot of bugs turn out to be people unsure how to use the table) but i must have forgotten to add the type when i added my last message

Oli :)

I have just pushed a fix to the master branch for this and will include it in todays patch release,

I took a step back and tried to understand your issues from a user interface perspective, all the talk of looking into the header filter system took me down the wrong path and was just a red heading.

The issue was that the editors were persisting their original starting value even after success (which is understandable, usually editors are destroyed after success) this meant that when you tabbed out of the emptied header filter it was checking to see if its value had changed against the original empty value and then concluding that the value hadn't changed so a cancel was called instead of a success. (thanks for the pointer on the success function not being called @aklaver)

I have made it so the editors now update the initial comparison value in case of success for when they are used as header filters.

Cheers

Oli :)

Hey @olifolkerd and @aklaver ,

Thanks for the support and fix. If this is resolved then the next thing related to this is #2107 . Because whenever people use multi column filter they always look forward to clear filters on a single button click rather than manually clearing each input field. And this single button click will have to call .clearHeaderFilter().

Thanks,
fingers10

Dear @olifolkerd ,

I tested this with v4.4.3. This issue still exists. With the same table configuration that I have shared above. If you call .clearHeaderFilter() and Tab through the header inputs and still ajax call to server is made for every tab press in search inputs.

In short, the below thing still fails

Now I'm pressing the Reset Search Button which in turn calls userGrid.clearHeaderFilter(); and now If I press Tab key from first column till last column, you can see the Ajax Search getting triggered for each column with empty array. - Bug.

Please reopen this and can you please assist further?

Thanks,
Abdul

Dear @olifolkerd,

Please reopen this as this issue is still not resolved in v4.4.3.

Thanks,
Abdul

There is no need to repeatedly message me. I have already asked you not to do this.

I will reopen this issue when I have had a chance to review your feedback (that you only left yesterday) and not before.

Please stop continually trying to force things through, it only serves to make me pay less attention to your issue.

If this issue is of such urgency to you please feel free to submit your own pull request.

I'm really sorry. Please don't take it in that sense. I'm not forcing. Again it's for tracking purpose, I'm asking to reopen. Not for immediate fix.

@fingers10

This is now a different issue, the header filters are now sending the correct requests back to the server, the issue now is about duplicate requests being triggered when the values are empty after the clear header filter.

While i agree that it is sub optimal, it should have no effect on users interacting with the table.

I would be happy to look into this but it is definitely different from the initial problem this was raised for

Cheers

Oli :)

Alright I'll open a separate issue for this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aballeras01 picture aballeras01  路  3Comments

tomvanlier picture tomvanlier  路  3Comments

Honiah picture Honiah  路  3Comments

tomheaps picture tomheaps  路  3Comments

KES777 picture KES777  路  3Comments