Custom Conditions

SearchBuilder allows you to create custom search inputs as discussed in the plug-in documentation. You can also use the searchBuilder.conditions option together with the plug-in API to customise the default search operations that SearchBuilder has build in. This document discusses techniques to do that, and also defines the build in search operations that you can work with.

SearchBuilder uses a series of objects to store its conditions in a clear and structured way. The first level of the condition object (searchBuilder.conditions or $.fn.dataTable.SearchBuilder.conditions) is a series of keys, representing the column types that DataTables automatically detects. You can find more details on these at columns.type. The build in types are:

  • string
  • date
  • num
  • num-fmt
  • html
  • html-num
  • html-num-fmt

In addition to the above, SearchBuilder has its own moment property that is used when Moment.js is used through the datetime-moment sorting plug-in. There is another very similar property that provides Luxon support through the datetime-luxon sorting plug-in. There is also an array property that provides conditions that are optimised for array like data. SearchBuilder will automatically detect and handle data in these columns, with the exception of the array conditions where the columns.type must be set to array. It is also possible to add your own column types to this object as well, again take a look at columns.type for more information on how to do this.

Each type is an object that defines the conditions that can be applied to data of that type. The actual name of the condition object isn't presented to the user at all, but it can be useful to name it so it helps the developer understand what the condition will do (e.g. = for a direct comparison condition).

Taking all of this into account means that the following basic structure is used no matter how you want to change the conditions. Here the num column type is used.

$('#example').DataTable({
    searchBuilder: {
        conditions: {
            num: {
                ...
            }
        }
    }
})

Throughout the rest of this page the num conditions will be used to demonstrate how to remove, edit and create conditions. The num conditions as standard are as follows:

  • = - Equals
  • != - Not Equals
  • !null - Not Null
  • < - Less Than
  • <= - Less Than Equal To
  • > - Greater Than
  • >= - Greater Than Equal To
  • null - Empty/null
  • between - Between
  • !between - Not Between

Removing a condition

Removing a condition is the most straightforward way to edit the conditions. If you want to remove the !between condition for example you would simply set that condition to null within the searchBuilder.conditions.num object:

$('#example').DataTable({
    searchBuilder: {
        conditions: {
            num: {
                '!between': null
            }
        }
    }
})

Or to remove it from all tables use:

delete $.fn.dataTable.SearchBuilder.conditions.num['!between'];

This will remove the "Not Between" condition from the list of conditions that are presented to the user when the a column of type num is selected.

Editing a condition

Within each condition there are five properties that can be edited to affect behaviour.

conditionName

searchBuilder.conditions[type].conditionName is the string value that is displayed to the user in the condition select element for each condition. The documentation for how to edit the placeholder for the select element is available at language.searchBuilder.condition. To edit the display string of the > condition from Greater Than to Above you would do the following.

$('#example').DataTable({
    searchBuilder: {
        conditions: {
            num: {
                '>': {
                    conditionName: 'Above'
                }
            }
        }
    }
})

Or for all tables:

$.fn.dataTable.SearchBuilder.conditions.num['>'].conditionName = 'Above';

init

The searchBuilder.condition[type].init function is used to initialise any jQuery elements that are required to retrieve values from the user for this condition. The standard searchBuilder.condition[type].init function for an input element is shown below.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                '>': {
                    init: function(that, fn, preDefined = null) {
                        // Declare the input element
                        let el = $('<input/>')
                            .addClass(that.classes.value)
                            .addClass(that.classes.input)
                            .on('input', function() { fn(that, this); });

                        // If there is a preDefined value then add it
                        if (preDefined !== null) {
                            $(el).val(preDefined[0]);
                        }

                        return el;
                    }
                }
            }
        }
    }
})

The searchBuilder.condition[type].init function takes three parameters.

  • that - This is the criteria instance that the condition is being set on. Passing this in allows for access to the classes and internal properties that are available and already in place. Note that changing the internal properties of the criteria instance here may lead to undefined behaviour.
  • fn - This is a callback function that must be called whenever you desire a search to take place. For an input element a search should trigger on every input into the input element. Therefore the function is called within a listener for input on the input element.
  • preDefined - This is where any values that are to be set or have previously existed in the value are passed. This is used by SearchBuilder so has to be in place, even if you are not setting a preDefined value. If you don't add this then it is likely that the input element will reset to be blank on every key press.

The searchBuilder.condition[type].init function returns the jQuery elements that are to be used to retrieve the values from the user. Multiple elements can be created here, if that is the case then an array of elements should be returned rather than a single element. It is also possible here to create more complex structures by appending elements to divs. The possibilities really are very wide.

Below is an example that shows an input element being returned inside a span with some custom classes applied.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                '>': {
                    init: function(that, fn, preDefined = null) {
                        // Declare span wrapper for input
                        var span = $('<span/>')
                            .addClass('mySpan');

                        // Declare the input element
                        var el = $('<input/>')
                            .addClass(that.classes.value)
                            .addClass(that.classes.input)
                            .addClass('myInput')
                            .on('input', function() { fn(that, this); });

                        // If there is a preDefined value then add it
                        if (preDefined !== null) {
                            $(el).val(preDefined[0]);
                        }

                        // Append input element to span
                        $(span).append(el);

                        return span;
                    }
                }
            }
        }
    }
})

inputValue

The searchBuilder.conditions[type].inputValue function is used to extract the values from the elements that were created in the searchBuilder.conditions[type].init function as detailed above. It is most likely that if you have made changes to the elements involved in the searchBuilder.conditions[type].init function then you will also have to make some changes to the searchBuilder.conditions[type].inputValue function.

Below is an example based on the jQuery structure listed above under the searchBuilder.conditions[type].init function. It takes two arguments.

  • el - The array of jQuery elements that were returned from the init function.
  • that - The criteria instance that is currently being considered.
$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                '>': {
                    inputValue: function(el, that) {
                        return [$(el[0]).children()[0].val()];
                    }
                }
            }
        }
    }
})

Here we are simply accessing the only child of the span, which is the input element. Then it's value can be read and returned.

isInputValid

The searchBuilder.conditions[type].inputValue function is used to determine whether the criteria should be included in the final search results. This is because we don't want to include incomplete or empty criteria, that could lead to unwanted results. The searchBuilder.conditions[type].inputValue function takes 2 parameters

  • el - The array of jQuery elements that were returned from the init function.
  • that - The criteria instance that is currently being considered.
$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                '>': {
                    isInputValid: function(el, that) {
                        return $(el[0]).children()[0].val().length > 0; // Check that the input element has some content
                    }
                }
            }
        }
    }
})

Here the input element is being checked to see that there is some content in the input element before the criteria is considered in the searching process. If you always wanted to consider the criteria no matter the values that have been gathered then simply return true from this function.

search

The searchBuilder.conditions[type].search function is used when searching the table to decide what results to include. It takes two parameters.

  • value - this is the value from the table that is to be compared. SearchBuilder automatically selects the correct dataPoint by using the data select element in the criteria.
  • comparison - This is the array of values that are returned from the searchBuilder.conditions[type].inputValue function.

Let's consider the between condition for this example. This condition takes two values in through two input elements. As standard it takes the form of:

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'between': {
                    search: function(value, comparison) {
                        // Depending on which input element is bigger will change the comparisons that need to be made
                        if (+comparison[0] < +comparison[1]) {
                            return +comparison[0] <= +value && +value <= +comparison[1];
                        }
                        else {
                            return +comparison[1] <= +value && +value <= +comparison[0];
                        }
                    }
                }
            }
        }
    }
})

Here any values from the table that lie between or on the comparison values will be shown in the table. Say the condition was to be edited so that only the values that lay between the comparison values and not on them were to be included, the following small change would take place to edit the condition.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'between': {
                    search: function(value, comparison) {
                        // Depending on which input element is bigger will change the comparisons that need to be made
                        if (+comparison[0] < +comparison[1]) {
                            return +comparison[0] < +value && +value < +comparison[1];
                        }
                        else {
                            return +comparison[1] < +value && +value < +comparison[0];
                        }
                    }
                }
            }
        }
    }
})

Creating a condition

Creating a condition is simply a matter of taking all of the properties that have been discussed in the Editing a condition section and pulling them all together. The following will detail how to create a "Multiple Of" filter. To create out filter we have to add an object to the num type object. This will mean something like the following.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'multiple': {
                    ...
                }
            }
        }
    }
})

conditionName

As previously discussed, searchBuilder.conditions[type].conditionName is simply the string that will be displayed in the condition select element.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'multiple': {
                    conditionName: 'Multiple Of'
                }
            }
        }
    }
})

init

For the searchBuilder.conditions[type].init function we don't need to use anything too complicated. A simple input element will perform well for this purpose. As well as declaring a jQuery input element, it is also necessary to set a listener for the callback function which introduces the searching functionality and create a mechanism to reload the preDefined values.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'multiple': {
                    conditionName: 'Multiple Of',
                    init: function (that, fn, preDefined = null) {
                        // Create input element and add the classes to match the SearchBuilder styles
                        var el = $('<input/>')
                            .addClass(that.classes.input)
                            .addClass(that.classes.value)

                        // Add the listener for the callback search function
                        $(el).on('input', function () {
                            fn(that, this);
                        });

                        // Set any preDefined values
                        if (preDefined !== null) {
                            el.val(preDefined[0]);
                        }

                        return el;
                    }
                }
            }
        }
    }
})

inputValue

Again, the searchBuilder.conditions[type].inputValue function can be fairly simple also, all we need to do is extract the value from the input element.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'multiple': {
                    conditionName: 'Multiple Of',
                    init: function (that, fn, preDefined = null) {
                        // Create input element and add the classes to match the SearchBuilder styles
                        var el = $('<input/>')
                            .addClass(that.classes.input)
                            .addClass(that.classes.value)

                        // Add the listener for the callback search function
                        $(el).on('input', function () {
                            fn(that, this);
                        });

                        // Set any preDefined values
                        if (preDefined !== null) {
                            el.val(preDefined[0]);
                        }

                        return el;
                    },
                    inputValue: function (el, that) {
                        // return the value in the input element
                        return [$(el[0]).val()];
                    }
                }
            }
        }
    }
})

isInputValid

Again, the searchBuilder.conditions[type].isInputValid function can be fairly simple. All that is required is to check that there is some text within the input element.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'multiple': {
                    conditionName: 'Multiple Of',
                    init: function (that, fn, preDefined = null) {
                        // Create input element and add the classes to match the SearchBuilder styles
                        var el = $('<input/>')
                            .addClass(that.classes.input)
                            .addClass(that.classes.value)

                        // Add the listener for the callback search function
                        $(el).on('input', function () {
                            fn(that, this);
                        });

                        // Set any preDefined values
                        if (preDefined !== null) {
                            el.val(preDefined[0]);
                        }

                        return el;
                    },
                    inputValue: function (el, that) {
                        // return the value in the input element
                        return [$(el[0]).val()];
                    },
                    isInputValid: function (el, that) {
                        return $(el).val().length > 0;
                    }
                }
            }
        }
    }
})

search

The searchBuilder.conditions[type].search function is where the condition is going to require the most "new" code. Although, having said this, it is still going to be fairly straight forward. To find out if a number is a multiple of another, we can just use the modulo (%) operator to check that the remainder is 0.

$('#example').DataTable({
    searchBuilder:{
        conditions:{
            num:{
                'multiple': {
                    conditionName: 'Multiple Of',
                    init: function (that, fn, preDefined = null) {
                        // Create input element and add the classes to match the SearchBuilder styles
                        var el = $('<input/>')
                            .addClass(that.classes.input)
                            .addClass(that.classes.value)

                        // Add the listener for the callback search function
                        $(el).on('input', function () {
                            fn(that, this);
                        });

                        // Set any preDefined values
                        if (preDefined !== null) {
                            el.val(preDefined[0]);
                        }

                        return el;
                    },
                    inputValue: function (el, that) {
                        // return the value in the input element
                        return [$(el[0]).val()];
                    },
                    isInputValid: function (el, that) {
                        return $(el).val().length > 0;
                    },
                    search: function (value, comparison) {
                        return value % comparison[0] === 0;
                    }
                }
            }
        }
    }
})

An example with this custom condition can be found here.

Another page that may be of interest is the SearchBuilder plug-in page