All Downloads are FREE. Search and download functionalities are using the official Maven repository.

butor.js.butor-live-search.js Maven / Gradle / Ivy

/*
 * Copyright 2013-2018 butor.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @class LiveSearch
 * @abstract
 * @memberof butor
 * @description
 * Set of methods to make a live search on some data.
 *
 * The live search can be binded on an input form in order to make a seach on target data, it is widely used as a suggestion tool when the user needs to find some informationon a table or on an attribute set.
 *
 * As an abstract class, this class needs to implemented and the following methods **needs** to be overriden in order to perform a live search on specific data:
 *  - {@link butor.LiveSearch#search `search`}
 *  - {@link butor.LiveSearch#read `read`}
 *
 * @param {jQueryElement} jqe - jQuery object.
 * @param {Map} options - Options of the live-search object.
 * @param {String} [options.id='id'] - ID of the searched items.
 * @param {String} [options.label='label'] - Displayed value in the live-search results.
 * @param {Event} [options.selectEvent='item-selected'] - Fired event when an item is selected.
 * @param {Number} [options.items=25] - Maximum number of displayed items in the 'dropdown'.
 * @param {Number} [options.minLength=2] - Number of characters which initiates the search.
 *
 * @example
 * 
* *
* * @example * butor.example = butor.example || {}; * * var beatles = [ * {code: 'John', descr: 'John Lennon - Vocals'}, * {code: 'Paul', descr: 'Paul McCartney - Vocals'}, * {code: 'Georges', descr: 'Georges Harrison - Guitar'}, * {code: 'Ringo', descr: 'Ringo Starr - Drums'} * ]; * * butor.example.LiveSearch = butor.example.LiveSearch || butor.LiveSearch.define({ * construct: function(jqe, options) { * this.base(jqe, options); * }, * * read: function(id, callback) { * var found = null; * * for (var i = 0; i < beatles.length; ++i) { * if (id === beatles[i]['id']) { * found = beatles[i]['id']; * break; * } * } * callback(found); * }, * search: function(id, callback) { * callback(beatles); * } * }); * * var options = { * 'id': 'code', * 'label': 'descr', * 'selectEvent': 'beatles-selected', * 'items': 10, * 'minLength': 4, * }; * * var liveSearch = new butor.example.LiveSearch($('.search'), options); * * liveSearch.bind('beatles-selected', function(e) { * $('p.beatles').text(e.data + ' is selected!'); * }); */ butor.LiveSearch = Butor.extend({ _typeaheadTimer: null, _typeaheadItems: {}, _jqe: null, _selected: null, // default values _options: { 'id': 'id', 'label': 'label', 'selectEvent': 'item-selected', 'items': 25, 'minLength': 2 }, construct: function(jqe, options) { this._jqe = jqe; this._options = $.extend(this._options, options); var self = this; // typeahead do not fire when emptying the field! this._jqe.change($.proxy(function() { if (butor.Utils.isEmpty(this._jqe.val())) { this._typeaheadItems = {}; this._selected = null; this.fire(this._options.selectEvent, null); } }, this)); // catch field exist without selection this._jqe.blur($.proxy(function() { var dn = this._jqe.val(); var item = this._typeaheadItems[dn]; if (!item) { if (this._selected) { this._jqe.val(this._selected[this._options.label]); } else { this._jqe.val(''); } } }, this)); this._jqe.typeahead({ autocomplete: false, //prevent default browser menus from appearing over the Bootstrap typeahead dropdown. items: this._options.items, minLength: this._options.minLength, source: function(query, process) { if (self._selected && self._typeaheadItems[query] == self._selected) { return; } self._typeaheadItems = {}; if (butor.Utils.isEmpty(query)) { self._selected = null; self.fire(self._options.selectEvent, null); return; } // bootstrap Typeahead is to fast. delaying... if (self._typeaheadTimer != null) { clearTimeout(self._typeaheadTimer); } self._typeaheadTimer = setTimeout(function() { self._typeaheadTimer = null; self._showSpinner(); self.search(query, function(data) { self._hideSpinner(); var items = []; if (!data) { process(items); return; } for (var ii = 0; ii < data.length; ii++) { var item = data[ii]; var dn = item[self._options.label]; items.push(dn); self._typeaheadItems[dn] = item; } process(items); if (items.length == 0) { self._jqe.css('color', 'red'); self._selected = null; self.fire(self._options.selectEvent, null); } else { self._jqe.css('color', ''); } }); }, 500) }, sorter: function(items) { return items.sort(); }, matcher: function(item) { return true; }, updater: function(dn) { var item = self._typeaheadItems[dn]; self._selected = item; if (!item) { return; } self._jqe.val(dn); self.fire(self._options.selectEvent, item[self._options.id]); return dn; } }); }, /** * @method _showSpinner * @memberof butor.LiveSearch# * @access private * @description Shows the spinner. */ _showSpinner: function() { var spinner = this._jqe.parent().find('.fa-spin'); if (spinner.length == 0) { spinner = $( '' ).hide(); spinner.appendTo(this._jqe.parent()); } var os = this._jqe.offset(); this._jqe.css('position', 'relative'); spinner.css({ 'bottom': 10, 'right': 18 }).show(); }, /** * @method _hideSpinner * @memberof butor.LiveSearch# * @access private * @description Hides the spinner. */ _hideSpinner: function() { this._jqe.parent().find('.fa-spin').hide(); }, /** * @method search * @memberof butor.LiveSearch# * @description Clears the live search field. * @param {jQuerySelector} text - jQuery selector. * @param {Function} callback - Callback of the search request. */ //TODO Parameters undefined! search: function(text, callback) { alert('No options.search(text, callback) provided!'); callback && callback(null); }, /** * @method read * @memberof butor.LiveSearch# * @description Reads the selected element by its ID. * @param {Number} id - ID of the search. * @param {Object} callback - Callback for the search request. */ //TODO Parameters undefined! read: function(id, callback) { alert('No options.read(id, callback) provided!'); callback && callback(null); }, /** * @method clear * @memberof butor.LiveSearch# * @description Clears the live-search. */ clear: function() { if (this._typeaheadTimer != null) { clearTimeout(this._typeaheadTimer); } this._selected = null; this._jqe.val(''); this.fire(this._options.selectEvent, null); }, /** * @method select * @memberof butor.LiveSearch# * @description Selects an element which matches with the ID. * @param {Number} id - ID of the element. */ select: function(id) { if (butor.Utils.isEmpty(id)) { this._jqe.val(''); this._selected = null; return; } var self = this; // set selected temporary self._selected = { 'id': id }; self._showSpinner(); self.read(id, function(data) { self._hideSpinner(); if (!data) { self._jqe.css('color', 'red'); self._selected = null; return; } self._selected = data; var dn = data[self._options.label]; self._typeaheadItems[dn] = data; self._jqe.val(dn); self.fire(self._options.selectEvent, data[self._options.id]); }); }, /** * @method getSelection * @memberof butor.LiveSearch# * @description Gets an object which is currently selected. * @return {Object} Selected object. */ getSelection: function() { return this._selected; } }); /** * item-selected event * * @event butor.LiveSearch#item-selected * @description This event is the default event sent by {@link butor.LiveSearch LiveSearch constructor}. * @param {String} id - ID of the selected item. */ //# sourceURL=butor-live-search.js




© 2015 - 2024 Weber Informatics LLC | Privacy Policy