Reputation: 2473
The following code performs an autocomplete for city and then selects the associated state. It works well if I follow the convention of Id: City and State. I'm running into situations where i have multiple city/state controls on a page with different ids.
Can someone please help me refactor this code to be more generic?
Thanks
$("#City").autocomplete({
source: function (request, response) {
$.ajax({
url: "http://ws.geonames.org/searchJSON?country=US",
dataType: "jsonp",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
name_startsWith: request.term
},
success: function (data) {
response($.map(data.geonames, function (item) {
return {
label: item.name + (item.adminName1 ? ", " + item.adminName1 : ""),
value: item.name,
code: item.adminCode1
}
}));
}
});
},
minLength: 2,
select: function (event, ui) {
$("#State").val(ui.item.code);
}
});
Upvotes: 1
Views: 2877
Reputation: 10989
It looks like your problem would be that when one #City
is autocompleted, all the #States
update to that one selection, eh? This is partly because you've violated an html rule. ID's are supposed to be unique.
So I would recommend the following:
Make your Id's unique, preferably named in a way that matches what they're for (like id="homecity"
, id="vacationcity"
etc.)
Add a class to your cities and states inputs that you're binding to.
Consider making your state inputs readonly
if they aren't already. That lets users know that they aren't supposed to type there and prevents UI events and interactions. Hopefully it doesn't disrupt the autocomplete plugin.
Add an attribute to the markup for the cities to indicate which state input they'll be modifying.
Tying it all together, because I can't put code samples in the middle of the list apparently...
Html:
<input id="homecity" class="autocomplete-city" stateid="homestate"></input>
<input id="homestate" class="autocomplete-state" readonly="readonly"></input>
Javascript:
$(".autocomplete-city").autocomplete({
source: function (request, response) {
$.ajax({
// your normal ajax stuff
});
},
minLength: 2,
select: function (event, ui) {
// Updated. 'this' is captured in the closure for the function here
// and it is set to the dom element for the input. So $() turns it
// into a jQuery object from which we can get the stateid attr
$("#"+$(this).attr('stateid')).val(ui.item.code);
}
});
And viola! Each input is generically tied to the state they will control. No more conflicting ids and no more exploding event handlers.
You could also pull this off with jQuery data, if you don't like poluting your markup with non-standard attributes (by which I mean the stateid="homestate"
in the html section).
Edit: This next paragraph explanation wrong.
According to the docs, in the select
function, the ui.item
is the jQuery element for the input that has been autocompleted, so it should be the correct #homecity
and the attr
call should return the correct value for #homestate
(keeping with the example). But I've not tried it, so you might want to throw in some null and/or undefined checking in there.
Edit: the ui.item
param passed to the select
function is the item selected from the menu, not the jQuery object for the input element. ui
has the following structure:
Object {item: Object}
item: Object
code: "AK"
label: "Jeuno, Alaska"
value: "Jeuno"
The correct way to get the attr for the state to update is in from this
, captured in the closure of the select
function as the DOM element for the input. So running the jQuery function on it $(this)
gets you the jQuery object from which you can get your attr()
or data()
.
JSFiddle with multiple autocompletes here: http://jsfiddle.net/KBVxK/1/
Upvotes: 1