In this scenario I've got a textbox to which I have added autocomplete functionality. The kicker is that I want to dynamically change the source option of the AJAX call based on the value of a dropdown list. To do this I encapsulated the differences between the AJAX calls in an object of type Resolver
. The name
property of the Resolver object is the same as the text value coming from the dropdown list. I was looking for a way to make this a little cleaner. The code works, just looking for more extensible options as the project grows.
$(document).ready(function ()
{
//encapsulate the URL of the AJAX call
//the name property maps to a dropdown list value
//so if Drugs is chosen from the dropdown menu we look for the name property which = drugs
Resolver = function (name, url)
{
this.name = name;
this.url = url;
}
Resolver.prototype.resolve = function (request, response)
{
$.ajax(
{
type: "POST",
url: "Service.asmx/" + this.url,
data: JSON.stringify({ 'param': $('#auto').val() }),
dataType: "json",
contentType: "application/json",
success: function (data)
{
response(data.d);
},
error: function (xhr)
{
console.log(xhr.status);
}
});
}
//in the future I expect the Resolver object to have more properties
//this is the simplest example I could think of
var drugs = new Resolver('drugs', 'GetDrugNames');
var hospitals = new Resolver('hospitals', 'GetHospitalNames');
var resolverArray = [];
resolverArray.push(drugs);
resolverArray.push(hospitals);
//on the change even of the ddl we're looking for the index of the resolverArray
//which has the name name property as the value selected in the ddl.
$('#ddl').change(function ()
{
var target = $(this).val().toLowerCase();
var index = 0;
$.each(resolverArray, function (ix, val)
{
if (resolverArray[ix].name == target)
{
index = ix;
}
});
$('#auto').autocomplete(
{
source: function (request, response)
{
resolverArray[index].resolve(request, response);
}
});
});
});
1 Answer 1
One way to make it extensible is to make it reusable rather than stick it to one dropdown. You can even make it into a jQuery plugin so that it looks like this:
$('.someAutocompleteBox').dependentAutoComplete({
/* the selector of the element to monitor changes */
elementToMonitor : '.theElementToMonitor',
/* value set, which correspond to the value of the previous input */
sets : {
drugs : DRUG_URL,
hospitals : HOSPITAL_URL,
}
/* you can monitor depending on the event and which value to grab */
triggeringEvent : 'keyup',
propertyToCheck : 'value'
});
So in this example, I set .someAutocompleteBox
to change sets when a keyup
event is triggered from .theElementToMonitor
. Then the plugin will grab the property defined in propertyToCheck
and check it against the sets
object which URL to use as source. Pretty simple isn't it?
As for jQuery plugin creation, you can use the jQuery Boilerplate to start off with a template. Everything else is self-explanatory, which is:
In the
init()
function of your plugin code, attach an event stated bytriggeringEvent
to the element stated byelementToMonitor
.When the event is fired, the handler should grab the value of the property defined in
propertyToCheck
.Do a lookup from the passed
sets
property and grab the URL of the corresponding key (which is the value grabbed from the property earlier)Update the current element's autocomplete source.
The plugin code (in the init
) should look something like this:
init: function () {
// nothing to check, nothing to check against
if(!this.settings.elementToMonitor || !this.settings.sets) return;
// Save the context
var instance = this;
// Attach the defined event to defined dependency
$(this.settings.elementToMonitor)
.on(this.settings.triggeringEvent,function(){
// Get the value at defined property
var value = $(this).prop(instance.settings.propertyToCheck);
var url;
// Check if we have that url in the set, return if not
if(!(url = instance.set[value])) return;
// Update the source accordingly
$(instance.element).autocomplete({
source = url;
});
});
}
-
\$\begingroup\$ I see several things I can use in here to improve upon. Great stuff! \$\endgroup\$wootscootinboogie– wootscootinboogie2013年10月08日 12:33:30 +00:00Commented Oct 8, 2013 at 12:33
JSON.stringify
when passing an object as thedata
property to jQ's$.ajax
, jQ will do that for you \$\endgroup\${ param: $('#auto').val() }
to the data property will sent the$('#auto').val()
value as$_POST['param']
... the request will look like this:param=<encodeURI($('#auto').val()>
, so no need to decode/parse the data \$\endgroup\${ param: $('#auto').val() }
to work. I'm using .NET 4.0 and get anInvalidJsonPrimitive
error. \$\endgroup\$x-www-form-urlencoded
mime \$\endgroup\$