0

I have successfully modified the snippet from this blog post.

In order to only match the beginning of one object value:

$.ui.autocomplete.filter = function(array, term) { var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(term), "i"); return $.grep(array, function(value) { return matcher.test(value.value); }); }; 

I would like to be able to match on two object values - the object value and description, eg: searching for "01" should return object's 1 and 3:

var array_of_objects = [ {value: "01000", product_desc: "a unique orange from spain"}, {value: "02000", product_desc: "a unique pear from spain 01"}, {value: "02001", product_desc: "01000 desc starts with number"}]; 

jsFiddle

Edit:

This answer looks up on two values, so I could possibly merge it with my jsFiddle solution, but I just need it to match beginning only.

Edit 2:

I've updated my original fiddle and it seems to be doing what is required, but I'm not sure if it's the most efficient way to do it or if it's cluttering up the dom a lot :/.

1 Answer 1

0

I think I came up with something cooler and more relevant to what I actually needed to do - it matches at the beginning of the value string or anywhere in the product_desc string.

The forked jsFiddle is highly commented so those wanting to just do a lookup on two values (where the match is at the beginning of either string), can comment out some lines and achieve that effect.

I also implemented a number of other features:

  • Match highlighting
  • Display number of matches
  • Scrollable results area
  • Populate page elements with multiple values from an object
  • Templated results
  • Multiple instances on one page

These are also heavily commented so they can be removed or modified if required.

I would still appreciate confirmation that this is a relatively clean solution that does not clutter up the dom with two many divs (autocomplete seems to add lots of unused divs to the dom?)

JS

// BEGIN show message prompt requiring 2 characters $(".my_lookup").on("keyup", function() { var product_container = $(this).parent(); var $matches_count = product_container.find(".matches_count"); var $matches_text = product_container.find(".matches_text"); var input_length = $(this).val().length; if (input_length < 2 && input_length !== 0) { $(this).siblings(".matches_prompt").text("search requires min 2 characters").show(); $matches_count.text("").hide(); $matches_text.text("").hide(); } else if (input_length === 0 || input_length >= 2) { $(this).siblings(".matches_prompt").hide(); } }); // END show message prompt requiring 2 characters // BEGIN look up on two values solution // see: https://stackoverflow.com/a/15849692 function lightwell(request, response) { // request.term is what you typed // response is the data to suggest to the user // added the 'match_type' argument to hasMatch() to: // - check for match at beginning of object's 'value' string // - check for match anywhere in object's 'product_desc' string // BEGIN hasMatch() function function hasMatch(s, match_type) { // to match beginning of string only, // use: === 0 // see: https://stackoverflow.com/a/12482182 // originally was !==-1 // to match anywhere in the string, // use !==-1 // when match_type === "start", // below returns true if request.term is at the 0 index // of the object.value or object.product_desc string // when match_type === "anywhere", // returns true if at any index other than no index // original usage (anywhere) below // (remove 'match_type' argument and references to it): // return s.toLowerCase().indexOf(request.term.toLowerCase()) !== -1; // added conditional handling // BEGIN if match_type === "start" if (match_type === "start") { // check if typed in term is at the 0 index of object's 'value' string var is_at_start_of_string = s.toLowerCase().indexOf(request.term.toLowerCase()) === 0; if (is_at_start_of_string === true) { console.log("typed term is at start of value string"); } return is_at_start_of_string; } // END if match_type === "start" // BEGIN if match_type === "anywhere" else if (match_type === "anywhere") { // check if typed in term is at any index of object's 'product_desc' string var exists_in_string = s.toLowerCase().indexOf(request.term.toLowerCase()) !== -1; if (exists_in_string === true) { console.log("typed term exists in product_desc string"); } return exists_in_string; } // END if match_type === "anywhere" } // END hasMatch() function // declare variables, i and obj are undefined, matches is [] var i, obj, matches = []; // BEGIN get the index of the input being used // see: https://stackoverflow.com/a/11278006/1063287 var current_input_index = $(document.activeElement).parent().index() - 1; // END get the index of the input being used // BEGIN get refererences to dproduct relative dom elements var $product_container = $(".product_container").eq(current_input_index); var $matches_count = $product_container.find(".matches_count"); var $matches_text = $product_container.find(".matches_text"); // END get refererences to dproduct relative dom elements // BEGIN if the typed in term is nothing // pass an empty array to response() if (request.term === "") { console.log("this thing is happening"); // hide the matches count display $matches_count.text("").hide(); $matches_text.text("").hide(); response([]); return; } // END if the typed in term is nothing // get length of array_of_objects var array_of_objects_length = array_of_objects.length; // for each object in the array, call the hasMatch() function // and pass it the object's 'value' and 'product_desc' strings for (i = 0; i < array_of_objects_length; i++) { obj = array_of_objects[i]; // if either of the below conditions return true, // push the object to the matches array if (hasMatch(obj.value, "start") || hasMatch(obj.product_desc, "anywhere")) { matches.push(obj); } } // pass the matches array to response() // get the count of matches for display var matches_count = matches.length; console.log("matches length is: " + matches_count) if (matches_count === 0 || matches_count > 1) { var matches_text = " matches" } else if (matches_count === 1) { var matches_text = " match" } // display the count of matches $matches_count.text(matches_count).show(); $matches_text.text(matches_text).show(); response(matches); } // END look up on two values solution // BEGIN autocomplete $(".my_lookup").autocomplete({ // only show 5 results with scrollbar // from: http://anseki.github.io/jquery-ui-autocomplete-scroll maxShowItems: 5, source: lightwell, minLength: 2, // called on input blur if value has changed change: function(event, ui) { var product_container = $(this).closest(".product_container"); var $matches_count = product_container.find(".matches_count"); var $matches_text = product_container.find(".matches_text"); $matches_count.text("").hide(); $matches_text.text("").hide(); }, // called when selecting an option select: function(event, ui) { // get references to product relative selectors var product_container = $(this).closest(".product_container"); var product_desc = product_container.find(".product_desc"); var product_type = product_container.find(".product_type"); var product_attr_01 = product_container.find(".product_attr_01"); var product_attr_02 = product_container.find(".product_attr_02"); var $matches_count = product_container.find(".matches_count"); var $matches_text = product_container.find(".matches_text"); $matches_count.text("").hide(); $matches_text.text("").hide(); // add object's values to relative product container inputs product_desc.val(ui.item.product_desc); product_type.val(ui.item.product_type); product_attr_01.val(ui.item.product_attr_01); product_attr_02.val(ui.item.product_attr_02); // BEGIN animate realtive inputs when selecting an option product_desc.animate({ "backgroundColor": "#d0e4ff" }, { "queue": false, "duration": 800 }); product_desc.animate({ "borderColor": "#7190dd" }, { "queue": false, "duration": 800 }); product_type.animate({ "backgroundColor": "#d0e4ff" }, { "queue": false, "duration": 800 }); product_type.animate({ "borderColor": "#7190dd" }, { "queue": false, "duration": 800 }); product_attr_01.animate({ "backgroundColor": "#d0e4ff" }, { "queue": false, "duration": 800 }); product_attr_01.animate({ "borderColor": "#7190dd" }, { "queue": false, "duration": 800 }); product_attr_02.animate({ "backgroundColor": "#d0e4ff" }, { "queue": false, "duration": 800 }); product_attr_02.animate({ "borderColor": "#7190dd" }, { "queue": false, "duration": 800 }); setTimeout(function() { product_desc.animate({ "backgroundColor": "#ffff" }, { "queue": false, "duration": 800 }); product_desc.animate({ "borderColor": "#cacaca" }, { "queue": false, "duration": 800 }); product_type.animate({ "backgroundColor": "#ffff" }, { "queue": false, "duration": 800 }); product_type.animate({ "borderColor": "#cacaca" }, { "queue": false, "duration": 800 }); product_attr_01.animate({ "backgroundColor": "#ffff" }, { "queue": false, "duration": 800 }); product_attr_01.animate({ "borderColor": "#cacaca" }, { "queue": false, "duration": 800 }); product_attr_02.animate({ "backgroundColor": "#ffff" }, { "queue": false, "duration": 800 }); product_attr_02.animate({ "borderColor": "#cacaca" }, { "queue": false, "duration": 800 }); }, 2000); // END animate realtive inputs when selecting an option }, // show fontawesome loading animation when search starts search: function(event, ui) { console.log("search started"); $(this).closest(".product_container").find(".fa-circle-o-notch").css("visibility", "visible"); }, // hide fontawesome loading animation when search finishes response: function(event, ui) { console.log("search finished"); $(this).closest(".product_container").find(".fa-circle-o-notch").css("visibility", "hidden"); }, // BEGIN add styles to results // from: https://gist.github.com/DBasic/9545690 create: function() { $(this).data('ui-autocomplete')._renderItem = function(ul, item) { // create a new 'value' string for match highlighting // see: https://stackoverflow.com/a/9889056/1063287 var newValueText = String(item.value).replace( // changed "gi" to i so that the match // on instance of search term is limited // to the first match, see: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp new RegExp(this.term, "i"), "<span class='ui-state-highlight'>$&</span>"); // create a new 'description' string for match highlighting var newDescText = String(item.product_desc.toUpperCase()).replace( new RegExp(this.term, "gi"), "<span class='ui-state-highlight'>$&</span>"); return $("<li></li>") .data("ui-autocomplete-item", item) // newValueText below used to be: item.value.toUpperCase() // newDescText below used to be: item.product_desc.toUpperCase() .append("<div class=\"my_result\"><span class=\"helper\"></span><img class=\"result_img\" src=\"https://placeimg.com/30/30/nature\">" + newValueText + " - " + newDescText + "</div>") .appendTo(ul); } } // END add styles to results }); // END autocomplete // new data set generated from https://github.com/Marak/faker.js var array_of_objects = [{ "value": "020101", "product_desc": "Handmade Frozen Pants", "product_type": "Automotive", "product_attr_01": "106.00", "product_attr_02": "171.00" }, { "value": "010101", "product_desc": "Practical Fresh Hat", "product_type": "Movies", "product_attr_01": "589.00", "product_attr_02": "777.00" }, { "value": "7099", "product_desc": "Awesome Concrete Sausages", "product_type": "Grocery", "product_attr_01": "249.00", "product_attr_02": "167.00" }, { "value": "5740", "product_desc": "Sleek Plastic Pizza", "product_type": "Home", "product_attr_01": "924.00", "product_attr_02": "379.00" }, { "value": "7627", "product_desc": "Intelligent Plastic Mouse", "product_type": "Games", "product_attr_01": "71.00", "product_attr_02": "412.00" }, { "value": "6606", "product_desc": "Handmade Steel Pizza", "product_type": "Music", "product_attr_01": "71.00", "product_attr_02": "791.00" }, { "value": "0973", "product_desc": "Intelligent Granite Tuna", "product_type": "Industrial", "product_attr_01": "25.00", "product_attr_02": "441.00" }, { "value": "5453", "product_desc": "Generic Steel Sausages", "product_type": "Sports", "product_attr_01": "887.00", "product_attr_02": "786.00" }, { "value": "3871", "product_desc": "Refined Wooden Keyboard", "product_type": "Sports", "product_attr_01": "897.00", "product_attr_02": "402.00" }, { "value": "9646", "product_desc": "Incredible Soft Chicken", "product_type": "Kids", "product_attr_01": "849.00", "product_attr_02": "438.00" }, { "value": "2948", "product_desc": "Licensed Plastic Gloves", "product_type": "Baby", "product_attr_01": "608.00", "product_attr_02": "748.00" }, { "value": "1561", "product_desc": "Sleek Steel Towels", "product_type": "Music", "product_attr_01": "315.00", "product_attr_02": "332.00" }, { "value": "5012", "product_desc": "Licensed Rubber Computer", "product_type": "Electronics", "product_attr_01": "886.00", "product_attr_02": "738.00" }, { "value": "4827", "product_desc": "Unbranded Wooden Shoes", "product_type": "Shoes", "product_attr_01": "390.00", "product_attr_02": "753.00" }, { "value": "0056", "product_desc": "Handcrafted Fresh Sausages", "product_type": "Shoes", "product_attr_01": "26.00", "product_attr_02": "257.00" }, { "value": "0628", "product_desc": "Fantastic Steel Tuna", "product_type": "Tools", "product_attr_01": "881.00", "product_attr_02": "127.00" }, { "value": "8498", "product_desc": "Gorgeous Soft Fish", "product_type": "Toys", "product_attr_01": "105.00", "product_attr_02": "604.00" }, { "value": "9265", "product_desc": "Gorgeous Wooden Cheese", "product_type": "Clothing", "product_attr_01": "257.00", "product_attr_02": "438.00" }, { "value": "0666", "product_desc": "Small Soft Keyboard", "product_type": "Baby", "product_attr_01": "960.00", "product_attr_02": "852.00" }, { "value": "4628", "product_desc": "Intelligent Plastic Car", "product_type": "Music", "product_attr_01": "598.00", "product_attr_02": "339.00" }, { "value": "3341", "product_desc": "Intelligent Metal Mouse", "product_type": "Garden", "product_attr_01": "92.00", "product_attr_02": "371.00" }, { "value": "6547", "product_desc": "Awesome Concrete Shirt", "product_type": "Health", "product_attr_01": "344.00", "product_attr_02": "145.00" }, { "value": "0803", "product_desc": "Unbranded Metal Chair", "product_type": "Kids", "product_attr_01": "343.00", "product_attr_02": "700.00" }, { "value": "9769", "product_desc": "Awesome Granite Bike", "product_type": "Home", "product_attr_01": "545.00", "product_attr_02": "391.00" }, { "value": "3087", "product_desc": "Refined Wooden Tuna", "product_type": "Industrial", "product_attr_01": "58.00", "product_attr_02": "68.00" }, { "value": "3202", "product_desc": "Small Concrete Gloves", "product_type": "Kids", "product_attr_01": "846.00", "product_attr_02": "60.00" }, { "value": "9638", "product_desc": "Generic Rubber Ball", "product_type": "Garden", "product_attr_01": "160.00", "product_attr_02": "123.00" }, { "value": "4762", "product_desc": "Tasty Frozen Computer", "product_type": "Health", "product_attr_01": "698.00", "product_attr_02": "832.00" }, { "value": "6606", "product_desc": "Rustic Frozen Shirt", "product_type": "Automotive", "product_attr_01": "867.00", "product_attr_02": "92.00" }, { "value": "6853", "product_desc": "Ergonomic Steel Pants", "product_type": "Sports", "product_attr_01": "712.00", "product_attr_02": "378.00" }, { "value": "5418", "product_desc": "Awesome Cotton Cheese", "product_type": "Toys", "product_attr_01": "483.00", "product_attr_02": "918.00" }, { "value": "0230", "product_desc": "Licensed Cotton Towels", "product_type": "Clothing", "product_attr_01": "540.00", "product_attr_02": "415.00" }, { "value": "3975", "product_desc": "Sleek Granite Pants", "product_type": "Outdoors", "product_attr_01": "823.00", "product_attr_02": "331.00" }, { "value": "7581", "product_desc": "Ergonomic Concrete Bacon", "product_type": "Automotive", "product_attr_01": "640.00", "product_attr_02": "718.00" }, { "value": "8550", "product_desc": "Practical Granite Table", "product_type": "Shoes", "product_attr_01": "94.00", "product_attr_02": "487.00" }, { "value": "3358", "product_desc": "Fantastic Plastic Computer", "product_type": "Clothing", "product_attr_01": "448.00", "product_attr_02": "440.00" }, { "value": "4586", "product_desc": "Ergonomic Steel Table", "product_type": "Games", "product_attr_01": "218.00", "product_attr_02": "806.00" }, { "value": "6331", "product_desc": "Intelligent Wooden Gloves", "product_type": "Shoes", "product_attr_01": "236.00", "product_attr_02": "546.00" }, { "value": "2871", "product_desc": "Handcrafted Wooden Salad", "product_type": "Beauty", "product_attr_01": "546.00", "product_attr_02": "259.00" }, { "value": "1648", "product_desc": "Tasty Soft Pants", "product_type": "Kids", "product_attr_01": "641.00", "product_attr_02": "251.00" }, { "value": "8096", "product_desc": "Practical Steel Chair", "product_type": "Toys", "product_attr_01": "609.00", "product_attr_02": "374.00" }, { "value": "5810", "product_desc": "Refined Steel Chicken", "product_type": "Kids", "product_attr_01": "529.00", "product_attr_02": "705.00" }, { "value": "7057", "product_desc": "Tasty Metal Mouse", "product_type": "Garden", "product_attr_01": "911.00", "product_attr_02": "935.00" }, { "value": "2344", "product_desc": "Intelligent Cotton Pizza", "product_type": "Sports", "product_attr_01": "705.00", "product_attr_02": "220.00" }, { "value": "9188", "product_desc": "Awesome Wooden Ball", "product_type": "Movies", "product_attr_01": "896.00", "product_attr_02": "850.00" }, { "value": "1474", "product_desc": "Sleek Plastic Salad", "product_type": "Tools", "product_attr_01": "15.00", "product_attr_02": "668.00" }, { "value": "6513", "product_desc": "Small Soft Chips", "product_type": "Health", "product_attr_01": "433.00", "product_attr_02": "74.00" }, { "value": "4036", "product_desc": "Unbranded Wooden Soap", "product_type": "Grocery", "product_attr_01": "826.00", "product_attr_02": "920.00" }, { "value": "9226", "product_desc": "Licensed Fresh Cheese", "product_type": "Industrial", "product_attr_01": "144.00", "product_attr_02": "102.00" }, { "value": "1944", "product_desc": "Fantastic Rubber Shoes", "product_type": "Electronics", "product_attr_01": "820.00", "product_attr_02": "808.00" }, { "value": "9379", "product_desc": "Small Wooden Tuna", "product_type": "Baby", "product_attr_01": "199.00", "product_attr_02": "160.00" }, { "value": "7888", "product_desc": "Handcrafted Frozen Sausages", "product_type": "Electronics", "product_attr_01": "70.00", "product_attr_02": "419.00" }, { "value": "1941", "product_desc": "Fantastic Granite Car", "product_type": "Grocery", "product_attr_01": "821.00", "product_attr_02": "853.00" }, { "value": "8322", "product_desc": "Licensed Wooden Fish", "product_type": "Games", "product_attr_01": "998.00", "product_attr_02": "703.00" }, { "value": "5586", "product_desc": "Fantastic Cotton Salad", "product_type": "Games", "product_attr_01": "887.00", "product_attr_02": "841.00" }]; /* code to generate the above data set, from: https://github.com/Marak/faker.js var array_of_objects = []; for (i = 0; i < 5; i++) { var obj = {}; obj['value'] = faker.fake("{{finance.mask}}"); obj['product_desc'] = faker.fake("{{commerce.productName}}"); obj['product_type'] = faker.fake("{{commerce.department}}"); obj['product_attr_01'] = faker.fake("{{commerce.price}}"); obj['product_attr_02'] = faker.fake("{{commerce.price}}"); array_of_objects.push(obj); } */ 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.