Replace search function entirely, not just $.fn.dataTable.ext.search.push

Replace search function entirely, not just $.fn.dataTable.ext.search.push

jens.olssonjens.olsson Posts: 17Questions: 7Answers: 1

We have set the searching parameter to true and it works as expected.

However we want to cusomise the search function, depending on what is entered we would like to show and hide different rows and it is a bit more advanced than just searching the data for a string.

Now we have seen the $.fn.dataTable.ext.search.push function. It adds additional filtering. We would however like to replace the entire filtering function if possible so that we can get full control.

Is it possible to keep the search field, but replace the function used for filtering?

Answers

  • kthorngrenkthorngren Posts: 20,302Questions: 26Answers: 4,769
    edited January 2020

    You can do some advanced searches with the search plugin ($.fn.dataTable.ext.search.push). More than just strings. It does augment the builtin search functionality. In order to completely replace the search functionality you would need to modify the datatables.js file you are using. If that is something you would to do then @allan or @colin can guide you one what code to replace. However, I don't think that would be a good plan as it will be problematic to perform upgrades.

    Short of actually writing your own search function I suggest you develop a search plugin and eliminate the use of the Datatable search API - meaning remove the default search input and create your own. Then with your input event handler simply use draw() to draw the table. This will perform any Datatables searches whcih you won't have then execute the search plugins.

    Here is a simple example using checkbox searches:
    http://live.datatables.net/wenaxuti/1/edit

    Kevin

  • jens.olssonjens.olsson Posts: 17Questions: 7Answers: 1

    Thanks for the reply @kthorngren. I would love if there would be a setting for disabling the built in search.
    I am not keen at changing the source code of the library, feels hard to maintain. I tihnk however that making it possible ti disable the built in search method would be something very useful as this is not the first time I have got this need.

    A suggestion @allan: Could the default search function be put inside the $.fn.dataTable.ext.search array? If so I could actually do:
    $.fn.dataTable.ext.search.pop()
    and then
    $.fn.dataTable.ext.search.push() our own function

    or maybe even $.fn.dataTable.ext.search = [ our_search_function ]
    ?

    Kind regards
    Jens

  • kthorngrenkthorngren Posts: 20,302Questions: 26Answers: 4,769
    edited January 2020

    I don't think you will be able to disable the builtin search functionality nor pop it off the $.fn.dataTable.ext.search array. You can use dom to remove the default search input. Then make sure you don't use search(), column().search() or columns().search() to search Datatables. Doing this you will effectively eliminate the builtin search functionality.

    If you want help with the search plugin please describe what you are trying to do?

    Kevin

  • jens.olssonjens.olsson Posts: 17Questions: 7Answers: 1

    I tried now creating my own search field, but if I remove the standard search field by entering
    searching: false
    in datatables constructor, then my custom filter handler added by $.fn.dataTable.ext.search.push() is never called.

  • kthorngrenkthorngren Posts: 20,302Questions: 26Answers: 4,769

    I tried now creating my own search field, but if I remove the standard search field by entering
    searching: false

    I can see that. There would be no reason to run the search function if you disable it. Instead of using searching: false try using the dom option and leave out the f.

    Kevin

  • prantlfprantlf Posts: 4Questions: 0Answers: 0
    edited May 2020

    This is a valid request. If you want to customize the search behaviour of the search input field, you need to be able to replace the built-in search function.

    For example, you want to implement include and exclude assertions for space-delimited terms. Entering "+term1 -term2" should perform "include(term1) and exclude(term2)". If you push a custom search plugin, it will never be called, because the built-in search function will use the search string top match the data and always return false earlier.

    It is possible to place a custom input field to the page and filter the table by its API, but it is too much work. There is a perfectly usable input field for searching in the DataTable. The simplest way how to customize the search woudl be to just replace the built-in function, which just matches strings and returns true or false.

  • kthorngrenkthorngren Posts: 20,302Questions: 26Answers: 4,769

    This example disables the Datatables event handler for the default search input and creates its own. It uses draw() to draw the table which will invoke the search plugins.
    http://live.datatables.net/yisaqore/1/edit

    This example will always display rows with Edinburgh in the Office column plus searches for the the columns for the search input. Its not a complete example but gives an idea of how to bypass the Datatables search engine. However you can still use the search API's if desired.

    Kevin

  • prantlfprantlf Posts: 4Questions: 0Answers: 0
    edited May 2020

    Thank you, Kevin, for the cunning idea to unsubscribe the DataTables input listener! It is still not as robust as a search callback on the interface, because DataTables could start listening on the input event, for example, but it avoids patching DataTables and will probably survive unbroken for a long time.

    In the meanwhile, I patched _fnFilter to call a function (string, terms), which could be an inspiration for a public API like function (settings, searchData, input) : bool.

    --- node_modules/datatables.net/js/jquery.dataTables.js 1985-10-26 09:15:00.000000000 +0100
    +++ cmd/sazserve/sources/js/jquery.dataTables.js    2020-05-07 18:31:33.000000000 +0200
    @@ -4383,7 +4383,7 @@
         *  @param {bool} caseInsensitive Do case insenstive matching or not
         *  @memberof DataTable#oApi
         */
    -   function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
    +   function _fnFilterOld( settings, input, force, regex, smart, caseInsensitive )
        {
            var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
            var prevSearch = settings.oPreviousSearch.sSearch;
    @@ -4428,6 +4428,53 @@
                settings.aiDisplay = filtered;
            }
        }
    +  function _fnFilter (settings, input, force, regex, smart, caseInsensitive) {
    +    var displayMaster = settings.aiDisplayMaster
    +    if (!input) {
    +      settings.aiDisplay = displayMaster.slice()
    +    } else {
    +      const invalidated = _fnFilterData(settings)
    +      const prevSearch = settings.oPreviousSearch.sSearch
    +      if (invalidated || prevSearch != input || settings.bSorted) {
    +        settings.aiDisplay = displayMaster.slice()
    +      }
    +      const display = settings.aiDisplay
    +      const filtered = []
    +      for (let i = 0; i < display.length; ++i) {
    +        if (matchTerms(settings.aoData[ display[i] ]._sFilterRow, input)) {
    +          filtered.push(display[i])
    +        }
    +      }
    +      settings.aiDisplay = filtered
    +    }
    +  }
    +  function matchTerms (string, terms) {
    +    terms = terms.trim()
    +    if (!terms) return true
    +    const filters = terms
    +      .toLowerCase()
    +      .split(/\s+/)
    +      .map(term => (
    +        term.startsWith('-') ? { exclude: true, term: term.substr(1) } :
    +        term.startsWith('+') ? { term: term.substr(1) } : { term }))
    +    const data = string.trim().toLowerCase()
    +    for (const filter of filters) {
    +      if (filter.exclude) {
    +        if (filter.term.length) {
    +          if (data.includes(filter.term)) return false
    +        } else {
    +          if (!data.length) return false
    +        }
    +      } else {
    +        if (filter.term.length) {
    +          if (!data.includes(filter.term)) return false
    +        } else {
    +          if (data.length) return false
    +        }
    +      }
    +    }
    +    return true
    +  }
        
        
        /**
    
This discussion has been closed.