phdphd Posted November 12, 2020 Share Posted November 12, 2020 Hi All, I have the following autocomplete function : when the user enters at least one character, some js code triggers a query that retrieves all matching values from a database and displays them in a scrolling box. The js code that builds the list of items looks like this : list.append('<div onclick=" myfunction('+records[i].id+')">'+records[i].label+''); where id and label represent the 2 fields of the result set. When the user clicks an item, it triggers a js function that submits the form. That function simply starts like this function myfunction(a) { where a is the id of the selected item. All that works very well. Now I want to put the label in the input so that the choice of the user appears in there just before the form is submitted. So I made the two following changes : list.append('<div onclick=" myfunction('+records[i].id+','+records[i].label+')">'+records[i].label+''); and function myfunction(a,b) { document.getElementById('id_of_the_input').value=b; It does not work. The debugger says «Uncaught ReferenceError: XXXX is not defined » where XXXX is the string of the label. But if instead I use list.append('<div onclick=" myfunction('+records[i].id+','+records[i].id+')">'+records[i].label+''); Then the Id will appear in the input. I do not understand why the Id is taken into account, but not the label, since they are both processed at the same time when building the list of items. Thanks ! Quote Link to comment Share on other sites More sharing options...
kicken Posted November 12, 2020 Share Posted November 12, 2020 (edited) Because you're not quoting your label properly. You're going to be generating a function call that looks like myfunction(8, The world's best cider); That's invalid Javascript, your label needs to be inserted as a valid string literal so that you'd end up with a call that looks like: myfunction(8, 'The world\'s best cider'); Such a thing can be done, but it's pain to do and this whole approach is the wrong way to accomplish this anyway so you shouldn't bother trying to figure out how to quote your string. There are varying way's to do this more correctly, but the way that would closest resemble your current approach would be to create your div node and then attach a click handler to it using javascript. It appears you're using jQuery which makes this fairly easy to do. Based on your usage of record[ i ] I assume this code is inside a simple for loop that is iterating over your records array. Given that, you'd end up with something like this as a replacement: var div = $(document.createElement('div')); div.text(records[i].label); div.click(function(record){ return function(){ myfunction(record.id, record.label); }; }(records[i])); list.append(div); If you've never seen the type of function declaration being used in the .click() method, that's what's known as an Immediately Invoked Function Expression (IIFE). It basically creates a new anonymous function which is then immediately executed and it's return value (another function) is then used as the parameter to the .click() method. This whole mess is necessary to make sure you're referencing the correct record when the item is clicked. If you just used record[ i ] directly it would not work as by the time you can click on the div i would point beyond the end of your list. This is because every iteration shares the same variable scope and thus modifications made to variables inside that scope. The IIFE generates a new isolated variable scope to work around that. You can read more about this scoping issue over on Stackoverflow if you're interested, they also go over various solutions to it from the most modern to the classics. What I prefer to do is make use of either jQuery's .each() function or Array's .forEach() function to loop over my array's instead of a simple for loop. This causes every iteration of the loop to run inside it's own unique variable scope so you can easily just reference the current item. records.forEach(function(record){ var div = $(document.createElement('div')); div.text(record.label); div.click(function(){ myfunction(record.id, record.label); }); list.append(div); }); Edited November 13, 2020 by kicken 1 Quote Link to comment Share on other sites More sharing options...
phdphd Posted November 13, 2020 Author Share Posted November 13, 2020 Thanks a lot kicken for your clear and detailed answer! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.