views:

81

answers:

6

Hi all,

I've written a fairly basic jQuery plugin that takes an unordered list and creates a nice looking multi-selectable list. Calling it 'multiSelector', the plugin declaration looks like this:

jQuery.fn.multiSelector = function(options) {
    // plugin code
}

The plugin actually runs on a containing div with an unordered list inside (for css reasons, among others), so a typical use of this plugin looks like this:

var $listDiv = $('#listDiv') // div that contains unordered list
$listDiv.multiSelector();

It's working great, so I'm not having any problems creating the plugin. However, what I'd like to do now is provide the user with a way to get all selected items from their list. I've looked online for how to create functions from this plugin, and I can't really seem to find any ways to extend it with a function.

What would be great is to do something like this, where 'itemArray' is an array of strings based on the list item's id (or something):

var itemArray = $listDiv.multiSelector().getSelected();

I realize my logic here is probably way off, but I'm just looking for some guidance on how to accomplish this. Maybe I need to write a new jQuery function to handle this specific task, or maybe I can still tack it onto this multiSelector plugin somehow. Any help would be appreciated.

Thanks.

A: 

If your plugin returns a jQuery object, then you'd just write another jQuery function to do your "getSelected" operation.

Pointy
+1  A: 

You need to make your multiSelector function return an object that contains a getSelected function.

For example:

jQuery.fn.multiSelector = function(options) {
    var self = this;

    return {
        getSelected: function() { 
            return self.children('.Selected');
        },
        //Other methods
    };
}

Note that within the returned methods, the this keyword will refer to the object ypu returned, not the original jQuery object. To work around this, you'll need to save a reference to the original this object (self in my example)

Also note that this will break method chaining, meaning that you won't be able to write $(...).multiSelector().fadeIn(). (Obviously)

SLaks
Bad idea; by jQuery convention you should always return the jQuery object for method chaining.
meagar
There are some plugins that do it this way.
SLaks
@meagar: except that makes that the OP wouldn't be able to do what he wants. Not every jQuery method, let alone plugin, returns the jQuery object.
Matt Ball
A: 

I'm not that familiar with jQuery plugin development, but from what I understand about Javascript in general is that you just need to return an object that contains your desired methods at the end of your plugin code, like this:

jQuery.fn.multiSelector = function(options) {
    //plugin code
    ...
    return {
        ...
        getSelected: function(opts) {
            //do stuff
        },
        ...
    };
}
Matt Ball
A: 

I typically see properties implemented like this:

$listDiv.multiselector('option', 'property'); // get $listDiv.multiselector('option', 'property', 'value'); // set

And I'd imagine you could do something similar with a 'selected' property. Kind of cumbersome, I realize.

As an example, see UI/Droppable's "methods", which are all accessed via .droppable("method_name").

What you shouldn't do, is return an object that has a getSelected() method, as several answers are suggesting (unless you add said method to the jQuery object). JQuery plugins are expected to return the jQuery object, and deviating from this will cause you grief in the long run, and make your code harder to use.

meagar
+2  A: 

I'd suggest adding the option to call a method as a parameter of the plugin. This is the way most (all?) jQuery UI plugins handle it.

jQuery.fn.multiSelector = function( options ) {
   if (typeof options === "string") {
      if (options == "selected") {
         ...return the selected elements
      }
      return null;
   }

   options = $.extend( {}, $.fn.multiSelector.defaults, options );

   ... rest of plugin body...
}

Then call it as

var selected = $('.selector').multiSelector('selected');
tvanfosson
Actually, *most* plugins return the dom elements being modified (`#listdiv` in the OP's example). This allows for function chaining. Your approach is still valid though.
Joel Potter
@Joel -- Sorry if I wasn't clear. Yes, the plugin should return jQuery, except when passed a method name to execute. So, without parameters or when passed an options object, it works like normal and sets up the plugin on the jQuery elements passed in. When passed a method name on a set of elements that have already been set up using the plugin, it executes the method and returns the method's results.
tvanfosson
@tvanfosson, thanks for the answer. This is most likely the approach I will use. But I'm wondering if there should be an 'else' after the `if (typeof options === "string") {`, just to handle the rest of the logic in the case 'options' is in fact a list of options and not the method call. What do you think?
Mega Matt
There is an "implicit" else -- if it doesn't take the if, then it simply continues. If it does take the if, then it always makes an early return from the function. That may not be clear since I couldn't fill in the details about how the selected elements are returned, but it should involve returning from the function.
tvanfosson
Makes sense. I guess, to me, returning early from a function feels a little clunky. I would just like to see a full chain of logic be run through, rather than having multiple return points from the same path. But that's just me. The way presented should work perfectly fine, and it's what I'll use. Thanks again!
Mega Matt
@Mega Matt -- in some ways I agree with you, but (1) it's also a somewhat clunky, albeit idiomatic way of invoking a function on a plugin, (2) invoking the function is clearly outside the main logic of plugin set up, and (3) it saves some, IMO, unnecessary indenting in the actual plugin set up code.
tvanfosson
A: 

Typically, plugins will usually provide this functionality by allowing the user to pass in a specific string as an argument to the plugin method that will cause the plugin to return something other than the usual jQuery object. For example,

$('#listDiv').multiSelector('getSelected') // will return an array of strings
Russ Cam