Skip to content

Instantly share code, notes, and snippets.

@dibley1973
Last active December 24, 2015 07:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dibley1973/60d65b8ccca8af856b93 to your computer and use it in GitHub Desktop.
Save dibley1973/60d65b8ccca8af856b93 to your computer and use it in GitHub Desktop.
Slickgrid Extension to create a simple searchable grid
/*
/ File: slickgrid.extensions.js
/ Requires: JQuery
/ SlickGrid
*/
(function ($) {
// Register namespace
$.extend(true, window, {
"Slick": {
"SimpleFilteredGridBuilder": SimpleFilteredGridBuilder
}
});
function SimpleFilteredGridBuilder(options) {
var _grid;
var _columns = [];
var _gridOptions;
var _filter;
var _dataView;
var _$searchTextField;
var _searchString;
var _guard = new Guard();
var _options;
var defaults = {
data: [],
gridSelector: "",
searchTextFieldSelector: "",
searchableColumnName: ""
};
guardArguments(options);
setOptions(options);
function guardArguments(options) {
_guard.argumentNotNullOrUndefined(options.data, "data");
_guard.argumentNotNullUndefinedOrEmpty(options.gridSelector, "gridSelector");
_guard.argumentNotNullUndefinedOrEmpty(options.searchTextFieldSelector, "searchTextFieldSelector");
_guard.argumentNotNullUndefinedOrEmpty(options.searchableColumnName, "searchableColumnName");
}
function setOptions(options) {
_options = $.extend(defaults, options);
}
function buildGrid() {
/// <summary>
/// Builds the grid, once columns have been set.
/// </summary>
try {
initSearchField();
initFilter();
initDataView();
initGridOptions();
initGrid();
} catch (e) {
throw new Error("Failed to initialise grid. " + e.message);
}
}
function initSearchField() {
_$searchTextField = $(_options.searchTextFieldSelector);
if (!textSearchFieldExists)
throw new Error("No text search field exists for selector '" + searchTextFieldSelector + "'");
bindSearchFieldHandlers();
setSearchStringFromField();
}
function textSearchFieldExists() {
return _$searchTextField.length > 0;
}
function bindSearchFieldHandlers() {
_$searchTextField.on("keyup change", filterDataView);
}
function setSearchStringFromField() {
_searchString = _$searchTextField.val().toLowerCase();
}
function withAutoColumns() {
/// <summary>
/// Automatically creates columns from the properties of the
/// first row object. Existing columns will be cleared first!
/// </summary>
var data = _options.data;
var noData = (data.length === 0);
if (noData) throw new Error("Cannot create auto columns when no data is present! ");
clearColumns();
var firstRow = data[0];
createColumnsFromRow(firstRow);
}
function createColumnsFromRow(row) {
for (var property in row) {
if (row.hasOwnProperty(property)) {
var column = createColumnFromProperty(property);
withColumn(column);
}
}
}
function createColumnFromProperty(property) {
return {
name: property,
field: property,
id: property
}
}
function clearColumns() {
/// <summary>
/// Clears the columns array. Only need to be called if columns have been
/// added with `withColumn(column)`
/// </summary>
_columns = [];
}
function withColumn(column) {
/// <summary>
/// Adds the specified column to the columns array.
/// </summary>
if (column == null) throw new Error("column must not be null. ");
_columns.push(column);
}
function getGrid() {
/// <summary>
/// Returns a reference to the grid.
/// </summary>
return _grid;
}
function filterDataView() {
_searchString = $(this).val().toLowerCase();
_dataView.refresh();
}
function initFilter() {
_filter = filter;
}
function initDataView() {
var dataView = new Slick.Data.DataView();
dataView.beginUpdate();
dataView.setItems(_options.data, _options.searchableColumnName);
dataView.setFilterArgs({ searchString: _searchString });
dataView.setFilter(_filter);
dataView.endUpdate();
dataView.onRowCountChanged.subscribe(onRowCountChanged);
dataView.onRowsChanged.subscribe(onRowsChanged);
_dataView = dataView;
}
function onRowsChanged(e, args) {
_grid.invalidateRows(args.rows);
_grid.render();
}
function onRowCountChanged() {
_grid.updateRowCount();
_grid.render();
}
function initGridOptions() {
_gridOptions = {
forceFitColumns: true,
autoSizeColumns: true,
enableColumnReorder: false
}
}
function initGrid() {
ensureColumnsExist();
_grid = new Slick.Grid(
_options.gridSelector,
_dataView,
_columns,
_gridOptions);
_grid.render();
}
function ensureColumnsExist() {
if (_columns.length === 0) {
throw new Error("Columns must be set before building the grid. " +
"Please use the 'withColumn(column)' function to add each column. ");
}
}
function filter(item) {
var filterCriteriaMet = true;
var searchableString = item[_options.searchableColumnName].toLowerCase();
var orSearchDelimiter = ",";
var andSearchDelimiter = " ";
var searchString = _searchString;
var performOrSearch = (searchString.indexOf(orSearchDelimiter) !== -1);
var performAndSearch = (searchString.indexOf(andSearchDelimiter) !== -1);
if (performOrSearch) {
//Option A - When the search string includes a comma, treat it as an OR search, e.g. expand the results
filterCriteriaMet = orSearchHasMatch(searchableString);
} else if (performAndSearch) {
// Option B - When the search string includes a space, treat it as an AND search, e.g. restrict the results
filterCriteriaMet = andSearchHasMatch(searchableString);
} else {
// Option C - Single word exact match
var singleWordExactMatchNotFound = (searchString !== "" && searchableString.indexOf(searchString) === -1);
if (singleWordExactMatchNotFound) filterCriteriaMet = false;
}
return filterCriteriaMet;
}
function orSearchHasMatch(searchableString) {
var matchFound = false;
var searchStringItems = _searchString.split(",");
for (var index = 0; index < searchStringItems.length; index++) {
var trimmedItem = searchStringItems[index].trim();
var notEmpty = trimmedItem !== "";
var searchableStringContainsTrimmedItem = (searchableString.indexOf(trimmedItem) !== -1);
var matchOnTrimmedOrItemNotMet = (notEmpty && searchableStringContainsTrimmedItem);
if (matchOnTrimmedOrItemNotMet) {
matchFound = true;
break;
}
}
return matchFound;
}
function andSearchHasMatch(searchableString) {
var filterCriteriaMet = true;
var searchStringItems = _searchString.split(" ");
for (var index = 0; index < searchStringItems.length; index++) {
var trimmedItem = searchStringItems[index].trim();
var notEmpty = trimmedItem !== "";
var searchableStringDoesnotContainTrimmedItem = (searchableString.indexOf(trimmedItem) === -1);
var matchOnTrimmedAndItemNotMet = (notEmpty && searchableStringDoesnotContainTrimmedItem);
if (matchOnTrimmedAndItemNotMet) {
filterCriteriaMet = false;
break;
}
}
return filterCriteriaMet;
}
return { // public interface
clearColumns: clearColumns,
buildGrid: buildGrid,
getGrid: getGrid,
withColumn: withColumn,
withAutoColumns: withAutoColumns
}
}
function Guard() {
var argumentNotNullOrUndefined = function (value, argumentName) {
if (value === undefined || value === null)
throw new Error("[" + argumentName + "] must not be null or undefined! ");
}
var argumentNotNullUndefinedOrEmpty = function (value, argumentName) {
if (value === undefined || value === null ||
(value.length && value.length === 0))
throw new Error("[" + argumentName + "] must not be null, undefined or empty! ");
}
return { // public interface
argumentNotNullOrUndefined: argumentNotNullOrUndefined,
argumentNotNullUndefinedOrEmpty: argumentNotNullUndefinedOrEmpty
};
}
})(jQuery);
<html>
<head>
<!-- SlickGrid, JQuery and form scripts here -->
</head>
<body>
<div>
<input id="GridSearch" type="text">
</div>
<div>
<div id="GridContainer"></div>
</div>
</body>
<html>
var gridBuilderOptions = {
data: myFunkyJsonData,
gridSelector: "#GridContainer",
searchTextFieldSelector: "#GridSearch",
searchableColumnName: "SearchField"
};
var gridBuilder = new Slick.SimpleFilteredGridBuilder(gridBuilderOptions);
gridBuilder.withColumn({ name: "Field 1", field: "Field1", minWidth: 100, maxWidth: 200 });
gridBuilder.withColumn({ name: "Field 2", field: "Field2");
gridBuilder.withColumn({ name: "Field 3", field: "Field3", formatter: Slick.Formatters.YesNo);
gridBuilder.withColumn({ name: "SearchField", field: "SearchField", maxWidth: 1);
gridBuilder.buildGrid();
this.grid = gridBuilder.getGrid();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment