butor.js.butor-live-search.js Maven / Gradle / Ivy
The newest version!
/*
* 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;
}
});
this._hideSpinner();
},
/**
* @method _showSpinner
* @memberof butor.LiveSearch#
* @access private
* @description Shows the spinner.
*/
_showSpinner: function() {
this._jqe.removeClass('live-search-ready');
this._jqe.addClass('live-search-loading');
},
/**
* @method _hideSpinner
* @memberof butor.LiveSearch#
* @access private
* @description Hides the spinner.
*/
_hideSpinner: function() {
this._jqe.removeClass('live-search-loading');
this._jqe.addClass('live-search-ready');
},
/**
* @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