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 Tonull
- Empty/nullbetween
- Between!between
- Not Between
Note: Please also not that custom conditions are not supported when the serverSide
option is set to true.
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 forinput
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