2
\$\begingroup\$

I have developed a simple autocomplete module for search box in ecommerce website (http://www.cjcharles.com/) built over shopify. Now, as the CMS is commercial, I was forced to use its given API's only.

 /*
 The given function implements instant search for ecommerce websites
 built on shopify platform using its API. The purpose of this module is
 to list the names of all products whose properties contain the text entered in
 search box as substring. By clicking on any of the suggested name, the user will
 be directed to the product page.
 We have used shopify API which gives us products.json. One request contains a set of maximum
 250 products and can be passed with 'page' parameter for pagination.
 We have used jquery-ui for implementing autocomplete feature.
*/
var custom_autocomplete = function() {
 "use strict";
 /*
 productList contains a dictionary of list of product objects mapped with a page number.
 It stores the data fetched from the database.
 */
 var productList = {};
 /*
 promiseList contains a dictionary of list of promises mapped with a page number.
 */
 var promiseList = {};
 /*
 search_text_box is id of text box where autocomplete will be implemented.
 */
 var ref = $('#search_text_box');
 /*
 Loader to be shown while searching.
 */
 var searchingLoaderRef = $('#searchingLoader');
 /*
 id of the section where results will appear.
 */
 var resultListUlRef = $('#ui-id-1');
 /*
 url for calling list of 250 products for a given page.
 */
 var url = '/products.json?limit=250&page=';
 /*
 Page required to make a request, default is 1.
 */
 var page = 1;
 /*
 Maximum value of page which is required to make a request.
 */
 var pageMax = 10;
 /*
 list of results after filtering all product lists fetched from the url.
 */
 var result = [];
 /*
 The given function is used to check if products in a given product object list 
 pass through the criteria to get in result list. 
 The function takes 2 paramaters. First is data which is nothing but an array of
 product objects and second is text which is the value of search text box. Searching is case-insensitive and
 text is matched with the values of 5 properties of product object named:
 title, product_type, vendor, sku and handle. 
 Result in the form of array of objects is returned.
 */
 function filterResults(data, text) {
 text = text.toLowerCase();
 var len = data.length;
 var response = [];
 for(var i=0;i<len;i++) {
 var singleData = data[i];
 var title = singleData.title.toLowerCase();
 var product_type = singleData.product_type.toLowerCase();
 var vendor = singleData.vendor.toLowerCase();
 var sku = singleData.variants[0].sku.toLowerCase();
 var handle = singleData.handle;
 if(title.indexOf(text)>=0 || product_type.indexOf(text)>=0 || vendor.indexOf(text)>=0
 || sku.indexOf(text)>=0 || handle.indexOf(text)>=0) {
 response.push({id : handle, label : title })
 }
 }
 return response;
 };
 /*
 The given function calls 'filterResults' function for every set of product list returned
 after hitting the url and populate the main 'result' list.
 */
 function checkAndFilter(data, response, text, id) {
 if(data.length) {
 var currentResult = filterResults(data, text);
 if (currentResult.length) {
 result = result.concat(currentResult);
 }
 }
 };
 /*
 When the product list fetched from a request is filtered, the given function
 checks whether results should be shown to the user or not. 
 */
 function checkAndShowResponse(response, page) {
 if(result.length) {
 $('#ui-id-1').addClass('autoCompleteResultSection');
 searchingLoaderRef.hide();
 response(result);
 } else if(page == pageMax) { /* If all products are scanned and no result is found */
 $('#ui-id-1').removeClass('autoCompleteResultSection');
 searchingLoaderRef.hide();
 response(['No Search Result']);
 }
 }
 /*
 The given function creates a promise object for every page request for fetching 
 product list as JSON. The promise object is then stored in promiseList dictionary
 mapped with page.
 The promise when gets resolved filters the returned product list and 
 shows the result if found.
 */
 function populateProductList(page, response, text, id) {
 if(!(page in promiseList))
 promiseList[page] = $.ajax({
 url : url + page,
 dataType : 'json'
 });
 $.when(promiseList[page]).done(function(data, textStatus, xhr) {
 if(data) {
 data = data.products;
 productList[page] = data;
 checkAndFilter(data, response, text, id);
 checkAndShowResponse(response, page);
 }
 });
 }
 /*
 The given function start instant searching for the text entered in
 the text box. The function first checks if the product list for every page is 
 present in 'productList' variable and if not found, fetches the data from the 
 database and store the returned list. Fetcing is done in async manner.
 */
 function autoCompleteSearchExamTextBox(response, id, text) {
 for (var page=1; page<= pageMax; page++) {
 if (page in productList) {
 checkAndFilter(productList[page], response, text, id);
 checkAndShowResponse(response, page);
 }
 else { 
 populateProductList(page, response, text, id)
 } 
 }
 };
 /*
 Adding jquery ui autocomplete to the given text box.
 */
 function implementExamAutoComplete(id) {
 $(id).autocomplete({
 delay : 500,
 source : function(request, response) {
 $('#ui-id-1').hide();
 searchingLoaderRef.show();
 var text = $(id).val();
 page = 1;
 result = [];
 autoCompleteSearchExamTextBox(response, id, text);
 },
 select: function(event, ui) {
 window.location.href = '/products/' + ui.item.id;
 }
 });
 };
 implementExamAutoComplete('#search_text_box');
 return {
 productList : productList
 }
};
custom_autocomplete();

The challenge is I have to filter the text in front end only. So, I have to call the data from the database and then filter it to show relevant results. Also, one request can fetch maximum 250 products and we can pass "page" as parameter for pagination.

I have developed the module and is working fair as of now. It would be a great help for me if anyone could review the code and provide me his/her valuable feedback so that I can improve the module performance.

Any review can be valuable for me.

asked Jun 20, 2015 at 20:46
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$
  1. Don't put a comment before each variable at the top. I'd recommend separating them into related groups, and describing each of the variables in those groups in a comment at the top of each group.
  2. Why are you not using spaces in between operators in your for loops? For example, for(var i=0;i<=len;i++) would become the following: for(var i = 0; i <= len; i++).
  3. Why are you using var custom_autocomplete = function( ... ) { ... } at the top for function declarations, and function name( ... ) { ... } for other declarations? I'd recommend choosing one style or the other, and sticking with that.
  4. Finally, your variable names could be more descriptive. For example, I know that the variable len describes the length of a variable of some type, but what is it the length of? I'd recommend something like the following: var varNameLength = ... ;.
answered Jun 22, 2015 at 3:17
\$\endgroup\$
1
  • \$\begingroup\$ Thank you for the response. Also, can you please comment on the way auto suggest is working? I mean, as there is no backend to filter out results, I have to request for all data at client side and then filter. \$\endgroup\$ Commented Jun 22, 2015 at 7:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.