1
\$\begingroup\$

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);
                }
            });

        });
    });
\$\endgroup\$
6
  • \$\begingroup\$ You needn't, and probably shouldn't, call JSON.stringify when passing an object as the data property to jQ's $.ajax, jQ will do that for you \$\endgroup\$ Oct 8, 2013 at 9:52
  • \$\begingroup\$ @EliasVanOotegem how else will this work if the data property of the ajax call doesn't know what the name of the parameter in the web method is? \$\endgroup\$ Oct 8, 2013 at 12:36
  • \$\begingroup\$ passing { 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\$ Oct 8, 2013 at 14:53
  • \$\begingroup\$ @EliasVanOotegem I couldn't get { param: $('#auto').val() } to work. I'm using .NET 4.0 and get an InvalidJsonPrimitive error. \$\endgroup\$ Oct 8, 2013 at 15:25
  • \$\begingroup\$ That's because jQ doesn't send its data as JSON by default, but defaults to the x-www-form-urlencoded mime \$\endgroup\$ Oct 8, 2013 at 15:35

1 Answer 1

2
\$\begingroup\$

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 by triggeringEvent to the element stated by elementToMonitor.

  • 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;
      });
    });
}
\$\endgroup\$
1
  • \$\begingroup\$ I see several things I can use in here to improve upon. Great stuff! \$\endgroup\$ Oct 8, 2013 at 12:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.