Jump to content

Autocomplete : Cannot Insert The User's Choice In Input


Recommended Posts

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 !

 

 

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 by kicken
  • Great Answer 1
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.