How to change search function to accept any combination of words - javascript

When I try to search for the title of a product, it only shows results if it is either the exact words, one word, or a combination of consecutive words.
For example, if I'm trying to find the product blue flying car, the product does not show if I try searching for blue car. Basically I want my search to be fixed to accept different combinations. How can I do this?
var item_xlsx = './assets/data/products.xlsx';
var all_items = [];
var all_cats = [];
var subcats = [];
var catQuery = '';
var subCatQuery = '';
var titleQuery = '';
function load_data() {
// get query parameters
catQuery = get_param('cat');
subCatQuery = get_param('subcat');
titleQuery = get_param('searchtext');
$('#searchtext').val(titleQuery);
$('#cat').val(catQuery);
fetch(item_xlsx).then(function (res) {
if (!res.ok) throw new Error("fetch failed");
return res.arrayBuffer();
}).then(function (ab) {
var data = new Uint8Array(ab);
var workbook = XLSX.read(data, { type: "array" });
var first_sheet_name = workbook.SheetNames[0];
var worksheet = workbook.Sheets[first_sheet_name];
all_items = XLSX.utils.sheet_to_json(worksheet, { raw: true });
populate_cats();
populate_subcats(catQuery);
render_category_form();
render_search_form(catQuery, titleQuery, all_items);
render_search_summary(catQuery, titleQuery, all_items);
render_search_results(catQuery, titleQuery, all_items);
});
}
function get_param(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
}
/* Filter items and render search results */
function render_search_results(cat, query, items) {
let results = all_items.filter(function (value, index, self) { // filter by cat
if (!catQuery || catQuery === "") {
return true;
} else {
return value.cat == catQuery;
}
}).filter(function (value, index, self) { // filter by subcat
if (!subCatQuery || subCatQuery === "") {
return true;
} else {
return value.subcat == subCatQuery;
}
}).filter(function (value, index, self) { // filter by query
if (!titleQuery || titleQuery === "") {
return true;
} else {
var regex = new RegExp(titleQuery, "i");
return value.name.search(regex) != -1 || value.audience.search(regex) != -1;
}
})

Try to filter for each word in search query - this way the results will only contain these items which contain all the words searched.
Searching function example for tests:
// setting the test array values
var all_items = ['abba the cure metall', 'abba the best songs', 'blue car abba', 'moose egipt sand sun abba', 'sunny day the company', 'abba songs', 'egiptian culture songs', 'blue sunny skies', 'singing songs when sky is blue', 'in a car with abba', 'in a car with moose', 'moose is blue', 'matallic moose', 'best songs while driving a car', 'metall skies of egipt', 'sing a song with abba'];
// converting the array into arr of objects similar to those in your code
$.each(all_items, function(i,v){
all_items[i]= {name: v, audience: ''};
});
// display all elements
$.each(all_items, function(i,v){ $('#namesDiv').append( $('<div/>').text(v.name) ); });
//
$('form').submit(function(e){
e.preventDefault();
// setting the test query from input element
var titleQuery = $('#search').val();
// filter by query
var queryParts = titleQuery.split(/[^\w]+/g); // split the keywords
var result_items = $.extend(true, [], all_items); // copy all items to result array
for(var i=0; i<queryParts.length; i++){ // iterate through keywords
var regex = new RegExp(queryParts[i], "i");
// check if current keyword is a part of name if not remove the item from result array
result_items = result_items.filter(function (value, index, self) {
return regex.test(value.name) || regex.test(value.audience);
});
}
// show search results in console
console.clear();
console.info('found '+result_items.length+' items:');
console.log(JSON.stringify(result_items));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form><input id='search' value="song abba"><button type="submit">search</button></form>
<div id="namesDiv" style="padding-bottom:5em;"></div>
The searching code above when nested in your function will look like this:
/* Filter items and render search results */
function render_search_results(cat, query, items) {
var results = all_items.filter(function (value, index, self) { // filter by cat
if (!catQuery || catQuery === "") {
return true;
} else {
return value.cat == catQuery;
}
}).filter(function (value, index, self) { // filter by subcat
if (!subCatQuery || subCatQuery === "") {
return true;
} else {
return value.subcat == subCatQuery;
}
});
if (titleQuery) { // filter by query
var queryParts = titleQuery.split(/[^\w]+/g); // split the keywords from query
for(var i=0; i<queryParts.length; i++){ // iterate through keywords
var regex = new RegExp(queryParts[i], "i");
// check if current keyword is a part of name or audience if not remove the item from results array
results = results.filter(function (value, index, self) {
return regex.test(value.name) || regex.test(value.audience);
});
}
}
If you need to search whole words only - just play with regex - the above solution includes sub-string matches.

Related

How to check specific variable of all array objects

I have an array object with several variables. The objects are created by reading data from firebase.
// Initialize cloud firestore database
let db = firebase.firestore();
//Create a class to store object data
class Data{
constructor(ID,ame, type, location, address, category) {
this.ID = ID;
this.type = type;
this.location = location;
this.address = address;
this.category = category;
}
}
//Get all documents in collection
db.collection("Basic_Data").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
Data_t = new Data(doc.ID,doc.data().type,doc.data().location,doc.data().address,doc.data().category);
all_data.push(Data_t);
});
});
I need to filter the objects based on certain conditions and if multiple filters are selected I need objects that satisfy all the conditions. I have no issues filtering that. After filtering, I try to consolidate values from the different filtering process. But some objects satisfy multiple conditions and are therefore included multiple times (not just twice). Thankfully, every object has a unique ID which I can use to filter the duplicates. But how do I check if an object with the unique ID is already present in the array?
//Filter data by user selection
function dataFilter() {
if ((document.getElementById("filter1-chkBox").checked) || (document.getElementById("filter2-chkBox").checked) || (document.getElementById("filter3-chkBox").checked) || (document.getElementById("filter4-chkBox").checked)) {
if (document.getElementById("filter1-chkBox").checked) {
temp_data_m = all_data.filter(function(info) {
return info.condition1 == true;
});
}
if (document.getElementById("filter2-chkBox").checked) {
temp_data_w = all_data.filter(function(info) {
return info.condition2 == true;
});
}
if (document.getElementById("filter3-chkBox").checked) {
temp_data_d = all_data.filter(function(info) {
return info.condition3 == true;
});
}
if (document.getElementById("filter4-chkBox").checked) {
temp_data_h = all_data.filter(function(info) {
return info.condition4 == true;
});
}
//Consolidate all the filter results
temp_data = temp_data_m;
if (temp_data_m.length != 0) {
temp_data_m = [];
}
if (temp_data_w.length != 0) {
temp_data = temp_data.concat(temp_data_w);
temp_data_w = [];
}
if (temp_data_d.length != 0) {
temp_data = temp_data.concat(temp_data_d);
temp_data_d = [];
}
if (temp_data_h.length != 0) {
temp_data = temp_data.concat(temp_data_h);
temp_data_h = [];
}
//Remove duplicates
temp_data.forEach((info) => {
if (!filtered_data.ID.includes(info.ID)) {
filtered_data.push(info);
}
});
} else {
filtered_data = temp_data;
}
}
I am trying to use forEach() and includes() to remove duplicates but I can't access the variable 'ID' from my array. How do I check the ID of all existing elements in the array?
Did you try to use filter()?
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]

Parse boolean search query back to array

Is there any easy way to parse the following string to array. I can convert array to string but no idea how to convert back to array.
// Input
"Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
}
]
// Input
"(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
},
{
all: ["Keyword7", "Keyword8"],
any: ["Keyword9", "Keyword10"],
not: ["Keyword11", "Keyword12"]
}
]
First things first:
I don't validate the input. This answer gives you an approach. You should validate the input, especially since you say it comes from the user :)
We will make use of the matchRecursive function from this blog.
This function will help us group the correct parentheses.
var matchRecursive = function () {
var formatParts = /^([\S\s]+?)\.\.\.([\S\s]+)/,
metaChar = /[-[\]{}()*+?.\\^$|,]/g,
escape = function (str) {
return str.replace(metaChar, "\\$&");
};
return function (str, format) {
var p = formatParts.exec(format);
if (!p) throw new Error("format must include start and end tokens separated by '...'");
if (p[1] == p[2]) throw new Error("start and end format tokens cannot be identical");
var opener = p[1],
closer = p[2],
/* Use an optimized regex when opener and closer are one character each */
iterator = new RegExp(format.length == 5 ? "["+escape(opener+closer)+"]" : escape(opener)+"|"+escape(closer), "g"),
results = [],
openTokens, matchStartIndex, match;
do {
openTokens = 0;
while (match = iterator.exec(str)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(str.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
};
}();
Next, this is the algorithm I would use based on the data you provided:
we determine if we have 1st kind of input or 2nd type, by simply checking if str.startsWith("(");
we initialize the followings:
groupedItems for an array that will transform 2nd type of input into 1st type of input, so that we use the same code for both afterwards
returnArr for the returned data
We loop over the groupedItems and prepare an empty keywordObj
In this loop, we determine which are the any keywords by making use of the matchRecursive function and splitting the result after ' OR ' - the resulting items will be any items
For the rest of the keywords (all or not) we need to get to a single word - so we split again, this time after " ", the result of the split being an array of keywords
We loop over the keywords and determine if they are not keywords by checking if they start with -, otherwise we treat them as all keywords.
Here's the code for it:
function output(str){
var groupedItems = [];
if(str.startsWith("(")){
groupedItems = matchRecursive(str,"(...)");
} else {
groupedItems.push(str);
}
var returnArr = [];
for (var i = 0; i<groupedItems.length;i++){
var keywordObj = {all:[], any:[], not: []};
var thisGroup = groupedItems[i];
var arr = matchRecursive(thisGroup, "(...)");
if (arr.length != 1) throw new Error("unexpected input");
keywordObj.any = arr[0].split(" OR ");
var restOfKeywords = thisGroup.split(" (" + arr[0] + ") ");
for (var j = 0; j<restOfKeywords.length; j++){
var keyWords = restOfKeywords[j].split(" ");
for (var k = 0; k<keyWords.length;k++){
if (keyWords[k].startsWith("-"))
keywordObj.not.push(keyWords[k])
else
keywordObj.all.push(keyWords[k])
}
}
returnArr.push(keywordObj);
}
return returnArr;
}
// input "(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// output [{"all":["Keyword1","Keyword2"],"any":["Keyword3","Keyword4"],"not":["-Keyword5","-Keyword6"]},{"all":["Keyword7","Keyword8"],"any":["Keyword9","Keyword10"],"not":["-Keyword11","-Keyword12"]}]
Here is a solution https://codepen.io/anon/pen/NXMoqo?editors=0012
{
// test cases
// const input = 'Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6';
const input = '(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)';
// const input = '((Keyword1 OR Keyword2 OR Keyword3) Keyword4 Keyword6 -Keyword5 -Keyword7) OR (Keyword8 Keyword9 (Keyword10 OR Keyword11) -Keyword12 Keyword13 -Keyword14 -Keyword15)';
const output = [];
input.split(') OR (').forEach(group => {
let trimmedGroup = group.replace(/^\(/, '').replace(/\)$/, '');
let anyGroup = trimmedGroup.match(/\(.+\)/).join('').replace(/[OR\)\(]/g, '').match(/\w+/g);
let notGroup = trimmedGroup.match(/-\w+/g).map(element => element.replace('-', ''));
let allGroup = trimmedGroup.replace(/\(.+\)/g, '').replace(/-\w+/g, '').match(/\w+/g);
output.push({
all: allGroup,
any: anyGroup,
not: notGroup
});
});
console.log(output);
}
can you check this
var arr = [], obj = {any:[], not:[], all: []};
function splitString(str) {
var object = JSON.parse(JSON.stringify(obj));
var strArr = str.split(" ");
var i=0;
while(strArr.length !== 0 && i<10) {
newStr = strArr.splice(0, 1)[0];
if(newStr.indexOf("(") != -1) {
while(newStr.indexOf(")") == -1) {
object.any.push(newStr.replace(")", "").replace("(", ""))
strArr.splice(0, 1);
newStr = strArr.splice(0, 1)[0];
}
object.any.push(newStr.replace(")", ""))
} else if(newStr.indexOf("-") != -1) {
object.not.push(newStr.substring(1).replace(")", ""))
} else {
object.all.push(newStr.replace(")", ""))
}
i++;
}
arr.push(object)
}
function convertToObj(string){
if(string.indexOf(") OR ") !== -1){
string.split(") OR ").forEach(function(str){
splitString(str.substring(1));
});
} else {
splitString(string);
}
}
convertToObj("Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6")
convertToObj("(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)")
console.log(arr)

es6 code broken in es5

I have been trying to translate my code from es6 to es5 because of some framework restrictions at my work... Although I have been quite struggling to locate what the problem is. For some reason the code does not work quite the same, and there is no errors either ...
Can someone tell me If I have translated properly ?
This is the ES6 code :
function filterFunction(items, filters, stringFields = ['Title', 'Description'], angular = false) {
// Filter by the keys of the filters parameter
const filterKeys = Object.keys(filters);
// Set up a mutable filtered object with items
let filtered;
// Angular doesn't like deep clones... *sigh*
if (angular) {
filtered = items;
} else {
filtered = _.cloneDeep(items);
}
// For each key in the supplied filters
for (let key of filterKeys) {
if (key !== 'TextInput') {
filtered = filtered.filter(item => {
// Make sure we have something to filter by...
if (filters[key].length !== 0) {
return _.intersection(filters[key], item[key]).length >= 1;
}
return true;
});
}
// If we're at TextInput, handle things differently
else if (key === 'TextInput') {
filtered = filtered.filter(item => {
let searchString = "";
// For each field specified in the strings array, build a string to search through
for (let field of stringFields) {
// Handle arrays differently
if (!Array.isArray(item[field])) {
searchString += `${item[field]} `.toLowerCase();
} else {
searchString += item[field].join(' ').toLowerCase();
}
}
// Return the item if the string matches our input
return searchString.indexOf(filters[key].toLowerCase()) !== -1;
});
}
}
return filtered;
}
And this is the code I translated that partially 99% work ..
function filterFunction(items, filters, stringFields, angular) {
// Filter by the keys of the filters parameter
var filterKeys = Object.keys(filters);
// Set up a mutable filtered object with items
var filtered;
// Angular doesn't like deep clones... *sigh*
if (angular) {
filtered = items;
} else {
filtered = _.cloneDeep(items);
}
// For each key in the supplied filters
for (var key = 0 ; key < filterKeys.length ; key ++) {
if (filterKeys[key] !== 'TextInput') {
filtered = filtered.filter( function(item) {
// Make sure we have something to filter by...
if (filters[filterKeys[key]].length !== 0) {
return _.intersection(filters[filterKeys[key]], item[filterKeys[key]]).length >= 1;
}
return true;
});
}
// If we're at TextInput, handle things differently
else if (filterKeys[key] === 'TextInput') {
filtered = filtered.filter(function(item) {
var searchString = "";
// For each field specified in the strings array, build a string to search through
for (var field = 0; field < stringFields.length; field ++) {
// Handle arrays differently
console.log(field);
if (!Array.isArray(item[stringFields[field]])) {
searchString += item[stringFields[field]] + ' '.toLowerCase();
} else {
searchString += item[stringFields[field]].join(' ').toLowerCase();
}
}
// Return the item if the string matches our input
return searchString.indexOf(filters[filterKeys[key]].toLowerCase()) !== -1;
});
}
}
return filtered;
}
These two lines
searchString += `${item[field]} `.toLowerCase();
searchString += item[stringFields[field]] + ' '.toLowerCase();
are not equivalent indeed. To apply the toLowerCase method on all parts of the string, you'll need to wrap the ES5 concatenation in parenthesis:
searchString += (item[stringFields[field]] + ' ').toLowerCase();
or, as blanks cannot be lowercased anyway, just use
searchString += item[stringFields[field]].toLowerCase() + ' ';
Here is a translated code from babeljs itself, as commented above.
'use strict';
function filterFunction(items, filters) {
var stringFields = arguments.length <= 2 || arguments[2] === undefined ? ['Title', 'Description'] : arguments[2];
var angular = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
// Filter by the keys of the filters parameter
var filterKeys = Object.keys(filters);
// Set up a mutable filtered object with items
var filtered = void 0;
// Angular doesn't like deep clones... *sigh*
if (angular) {
filtered = items;
} else {
filtered = _.cloneDeep(items);
}
// For each key in the supplied filters
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
var _loop = function _loop() {
var key = _step.value;
if (key !== 'TextInput') {
filtered = filtered.filter(function (item) {
// Make sure we have something to filter by...
if (filters[key].length !== 0) {
return _.intersection(filters[key], item[key]).length >= 1;
}
return true;
});
}
// If we're at TextInput, handle things differently
else if (key === 'TextInput') {
filtered = filtered.filter(function (item) {
var searchString = "";
// For each field specified in the strings array, build a string to search through
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = stringFields[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var field = _step2.value;
// Handle arrays differently
if (!Array.isArray(item[field])) {
searchString += (item[field] + ' ').toLowerCase();
} else {
searchString += item[field].join(' ').toLowerCase();
}
}
// Return the item if the string matches our input
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return searchString.indexOf(filters[key].toLowerCase()) !== -1;
});
}
};
for (var _iterator = filterKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
_loop();
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return filtered;
}
p.s. Or there is a better way to use babeljs directly without manually converting it.

Search in array of objects with object javascript

I have an array like this
var userdata = [
{"id":1,"gender":"M","first":"John","last":"Smith","city":"Seattle, WA","status":"Active"},
{"id":2,"gender":"F","first":"Kelly","last":"Ruth","city":"Dallas, TX","status":"Active"},
{"id":3,"gender":"M","first":"Jeff","last":"Stevenson","city":"Washington, D.C.","status":"Active"},
{"id":4,"gender":"F","first":"Jennifer","last":"Gill","city":"Seattle, WA","status":"Inactive"}
]
I need to filter this array on some conditions. The form of these conditions are like this.
var search_object = {gender:"M",city:"Seattle, WA"}
// Gender = M and city = 'Seattle, WA'
var search_object1 = {gender:"M"}
var search_object2 = {city:"Seattle, WA"}
// This is same as above
var search_array = {status:["Active","Inactive"]}
// Status Active or Inactive
var search_array = [{status:"Active"},{status:"Inactive"}]
// Same as above
var search_object1 = {gender:"F"}
var search_array = [{status:"Active"},{status:"Inactive"}]
//Gender = F and status = Active or Inactive
var search_object = {gender:"F"}
var search_array = [{status:["Active","Inactive"]}]
// same as above
I have tried looping but failed. Please help or suggest or provide some proper links to get help.
The following code covers all the cases you mentioned.
function search(searchObj, data) {
if(searchObj instanceof Array) {
return data.reduce(function(prev, current, index, array) {
return prev.concat(search(current, data));
}, []);
} else {
var results = data.filter(function(el) {
for(var prop in searchObj) {
if(searchObj[prop] instanceof Array) {
if(searchObj[prop].indexOf(el[prop]) == -1) {
return false;
}
} else
if(el[prop] !== searchObj[prop]) {
return false;
}
}
return true;
});
return results;
}
};
search(search_object, userdata);
Here is the working example in JSFiddle.
And here are some links to the functions I've used above:
Array.prototype.reduce()
Array.prototype.concat()
Array.prototype.filter()
Array.prototype.indexOf()
Just what RGraham said in the comments, you can use the filter function on arrays.
var search_object = {gender:"M",city:"Seattle, WA"};
var filtered = userdata.filter(function(obj){
return (obj.gender === search_object && obj.city === search_object.city)
});
filtered[0];//Array with objects that return true;

Properly update the source Option in bootstrap-typeahead.js

In the following demo, after inserting "Alaska" value,
the source is updated so that the autocomplete is not showing again Alaska value.
var newSource = this.source
.slice(0,pos)
.concat(this.source.slice(pos+1));
this.source = newSource;
Anyway if I remove Alaska from the textarea, the value Alaska should be displayed again in the source.
Any hints how to restore the source data if the user delete the data from the textarea?
My idea is to access the options `source option from
$('.typeahead').on('change', function () { })
Any hints?
P.S.:
I am using jquery and underscore
You should probably rather change your matcher function in order to test over the already selected states :
var tabPresentStates = this.query.split(','),
nbPresentStates = tabPresentStates.length;
for(var iState = 0; iState < nbPresentStates; iState++) {
if(item === tabPresentStates[iState].trim())
return false;
}
See this fiddle.
Instead of changing the source you can use the sorter to exclude the values you've already selected.
http://jsfiddle.net/BwDmM/71/
P.S. I'll probably include your code in next version of Jasny's extended Bootstrap http://jasny.github.com/bootstrap :)
!function(source) {
function extractor(query) {
var result = /([^,]+)$/.exec(query);
if(result && result[1])
return result[1].trim();
return '';
}
$('.typeahead').typeahead({
source: source,
updater: function(item) {
return this.$element.val().replace(/[^,]*$/,'')+item+',';
},
matcher: function (item) {
var tquery = extractor(this.query);
if(!tquery) return false;
return ~item.toLowerCase().indexOf(tquery)
},
highlighter: function (item) {
var query = extractor(this.query).replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>'
})
},
sorter: function(items) {
var beginswith = []
, caseSensitive = []
, caseInsensitive = []
, existing = $.each(this.$element.val().split(','), function(i, val) { return val.trim() })
, item
while (item = items.shift()) {
if ($.inArray(item, existing) >= 0) continue;
if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
else if (~item.indexOf(this.query)) caseSensitive.push(item)
else caseInsensitive.push(item)
}
return beginswith.concat(caseSensitive, caseInsensitive)
}
});
}(["Alabama","Alaska","Arizona","Arkansas","California","Colorado","Connecticut","Delaware","Florida","Georgia","Hawaii","Idaho","Illinois","Indiana","Iowa","Kansas","Kentucky","Louisiana","Maine","Maryland","Massachusetts","Michigan","Minnesota","Mississippi","Missouri","Montana","Nebraska","Nevada","New Hampshire","New Jersey","New Mexico","New York","North Dakota","North Carolina","Ohio","Oklahoma","Oregon","Pennsylvania","Rhode Island","South Carolina","South Dakota","Tennessee","Texas","Utah","Vermont","Virginia","Washington","West Virginia","Wisconsin","Wyoming"]);
Agreed with #SamuelCaillerie's approach to use matcher - this is just using your extractor function. So:
updater: function(item) {
return this.$element.val().replace(/[^,]*$/,'')+item+',';
},
matcher: function (item) {
var previouslySelected = (this.query.indexOf(item) != -1);
var tquery = (previouslySelected ? "" : extractor(this.query));
if(!tquery) return false;
return ~item.toLowerCase().indexOf(tquery)
},

Categories