Filter dropdown

How to create a custom dropdown filter for your table.

Note

The base table in the example below is a clone of the showcase example to demonstrate that the dropdown keeps the filter state across various table operations such as filtering, sorting, paging.

Step 1: Inheriting from the base filtering component

All core objects or "classes" in FooTable are derived from the FooTable.Class object. This object exposes a single method called extend which allows you to create a whole new class from a base class (inherit) or to simply override a single method on an existing class. In this example we will be inheriting the base FooTable.Filtering component, modifying it and then replacing, it with our modified version.

FooTable.MyFiltering = FooTable.Filtering.extend({ // inherit the base class
	construct: function(instance){ // override the default constructor
		this._super(instance); // call the base constructor
	}
});

// replace the existing component with our custom one
FooTable.components.core.register('filtering', FooTable.MyFiltering);

Step 2: Add custom properties for the dropdown

To make the code more maintainable going forward and easier to understand we will add some properties to our custom filtering component to hold the available options, the default option, and the jQuery wrapper around our dropdown.

FooTable.MyFiltering = FooTable.Filtering.extend({
	construct: function(instance){
		this._super(instance);
		this.statuses = ['Active','Disabled','Suspended']; // the options available in the dropdown
		this.def = 'Any Status'; // the default/unselected value for the dropdown (this would clear the filter when selected)
		this.$status = null; // a placeholder for our jQuery wrapper around the dropdown
	}
});

Step 3: Create the dropdown and append it to the table

To create the actual dropdown element and append it to the table we will override the $create method and generate our markup as required. The base filtering component exposes the property $form which is the jQuery wrapper for the form that contains the default search input. Using this we can simply create our dropdown and append it as required.

$create: function(){
	this._super(); // call the base $create method, this populates the $form property
	var self = this, // hold a reference to my self for use later
		// create the bootstrap form group and append it to the form
		$form_grp = $('<div/>', {'class': 'form-group'})
			.append($('<label/>', {'class': 'sr-only', text: 'Status'}))
			.prependTo(self.$form);

	// create the select element with the default value and append it to the form group
	self.$status = $('<select/>', { 'class': 'form-control' })
		.on('change', function(){
			self.filter(); // when ever the dropdown value changes trigger the filter operation
		})
		.append($('<option/>', {text: self.def}))
		.appendTo($form_grp);

	// add each of the statuses to the dropdown element
	$.each(self.statuses, function(i, status){
		self.$status.append($('<option/>').text(status));
	});
}

Step 4: Hooking into the filter operation

At this point we have the dropdown appearing next to the search input and it triggers a filter operation whenever it is changed however we need to hook into the filter operation to actually apply our custom filter. To do this we will override the base filtering components' filter method and use the addFilter and removeFilter methods to implement the status filter.

filter: function(query, columns){
	var val = this.$status.val(); // get the current dropdown value
	if (val != this.def) this.addFilter('status', val, ['status']); // if it's not the default value add a new filter
	else this.removeFilter('status'); // otherwise remove the filter
	return this._super(query, columns); // call the base filter method
}

Step 5: Hooking into the clear filter operation

So now we have the dropdown, it's applying the filter as required but we also need it to clear itself when we click the [X] button on the search input. To do this we will override the base filtering components' clear method and use the removeFilter method to remove the status filter.

clear: function(){
	this.$status.val(this.def); // reset the dropdown to the default value
	this.removeFilter('status'); // remove the filter
	return this._super(); // call the base clear method
}

Finished!

That's it! We now have a custom filter dropdown that is fully integrated with the rest of the filter functionality. The full code can be seen below.

FooTable.MyFiltering = FooTable.Filtering.extend({
	construct: function(instance){
		this._super(instance);
		this.statuses = ['Active','Disabled','Suspended'];
		this.def = 'Any Status';
		this.$status = null;
	},
	$create: function(){
		this._super();
		var self = this,
			$form_grp = $('<div/>', {'class': 'form-group'})
				.append($('<label/>', {'class': 'sr-only', text: 'Status'}))
				.prependTo(self.$form);

		self.$status = $('<select/>', { 'class': 'form-control' })
			.on('change', function(){
				self.filter();
			})
			.append($('<option/>', {text: self.def}))
			.appendTo($form_grp);

		$.each(self.statuses, function(i, status){
			self.$status.append($('<option/>').text(status));
		});
	},
	filter: function(query, columns){
		var val = this.$status.val();
		if (val != this.def) this.addFilter('status', val, ['status']);
		else this.removeFilter('status');
		return this._super(query, columns);
	},
	clear: function(){
		this.$status.val(this.def);
		this.removeFilter('status');
		return this._super();
	}
});

FooTable.components.core.register('filtering', FooTable.MyFiltering);