22
\$\begingroup\$

Over the last months I have been writing a jQuery plugin called Better Autocomplete (Code on Github). It originated from another project, a Drupal module called Linkit, but I decided it should be a standalone plugin. I have spent a lot of time refactoring the code, mainly to make it more generic and flexible for multiple purposes. I have now reached a point where it makes sense to actually ask for advice on the code, hopefully by professional, more experienced JavaScript developers.

EDIT: I read in the FAQ that I'm supposed to include some of the code. This is a shorter version of the code, describing the structure of the code. There is also documentation available.

(function ($) {

$.fn.betterAutocomplete = function(method) {

  var methods = {
    init: function(resource, options, callbacks) {
      var $input = $(this),
        bac = new BetterAutocomplete($input, resource, options, callbacks);
      $input.data('better-autocomplete', bac);
      bac.enable();
    },
    enable: function(bac) {
      bac.enable();
    },
    disable: function(bac) {
      bac.disable();
    },
    destroy: function(bac) {
      bac.destroy();
    }
  };

  var args = Array.prototype.slice.call(arguments, 1);

  // Method calling logic
  this.filter(':input[type=text]').each(function() {
    switch (method) {
        // ... Code here
    }
  });

  // Maintain chainability
  return this;
};

// This is the constructor function. Instantiated by using the new keyword
var BetterAutocomplete = function($input, resource, options, callbacks) {

  options = $.extend({
    charLimit: 3,
    // More options
  }, options);

  /**
   * These callbacks are supposed to be overridden by you when you need
   * customization of the default behavior. When you are overriding a callback
   * function, it is a good idea to copy the source code from the default
   * callback function, as a skeleton.
   */
  callbacks = $.extend({

    /**
     * Gets fired when the user selects a result by clicking or using the
     * keyboard to select an element.
     *
     * <br /><br /><em>Default behavior: Simply blurs the input field.</em>
     *
     * @param {Object} result
     *   The result object that was selected.
     */
    select: function(result) {
      $input.blur();
    },
    // ... More callbacks for fetching data, parsing results etc.
  }

  var self = this,
    lastRenderedQuery = '',
    results = {}, // Caching database of search results.
    // ... More private instance variables

  // Create the DOM elements necessary and attach eventhandlers
  var $wrapper = $('<div />')
      .addClass('better-autocomplete')
      .insertAfter($input);

  // Public methods
  this.enable = function() { ... };

  // Then private methods
  var fetchResults = function() { ... };

  var getHighlighted = function() { ... };
};

}(jQuery);

Some hands on questions:

  1. Does my design patterns look good? I am talking about modularity, namespacing, closures etc.
  2. How can I stand out more from jQuery UI autocomplete and other existing plugins? What can I provide that they can't? Also, where can I reach the people who need this plugin?
  3. Documentation. I have been using JSDoc toolkit but it is sometimes hard to understand. I have a few warnings when I generate the docs. Also I'm unsure about if I have correctly labeled functions, constructors etc. Can I improve it?

I can take criticism, so don't be shy, rather be honest.

\$\endgroup\$
  • 1
    \$\begingroup\$ Firstly: I can't help with JSDoc and i'm not a very experienced jQuery plugin Developer but on #2 I think you should be asking the users of your plugin. Provide an email/discussion board/whatever as they are the ones who know what is needed. Maybe ask them specific questions like what have they done to extend your plugin etc. \$\endgroup\$ – James Khoury Jun 27 '11 at 3:03
  • 1
    \$\begingroup\$ I do not want to put a damper on the work you have done, but I think that your hard work is better put helping one of the established projects become better other than starting a new fork. Just my $0.02 \$\endgroup\$ – Stephen Senkomago Musoke Apr 10 '12 at 6:44
5
\$\begingroup\$

You should strongly consider using a JS templating language such as Handlebars.js when rendering the interface.

  // Add the group if it doesn't exist
  var group = callbacks.getGroup(result);
  if ($.type(group) == 'string' && !groups[group]) {
    var $groupHeading = $('<li />').addClass('group')
      .append($('<h3 />').html(group))
      .appendTo($results);
    groups[group] = $groupHeading;
  }

  var $result = $('<li />').addClass('result')
    .append(output)
    .data('result', result) // Store the result object on this DOM element
    .addClass(result.addClass);

You are doing enough dom manipulation to warrant its use (above is just one part of your code). Furthermore, templates will help separate presentation logic from your business logic which at the moment is quite tangled.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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