pistou
pistou

Reputation: 2867

Split an object into arrays

I'm currently writing a library using jQuery, and I'm facing a wall I can't pass alone.

First, here is some code :

(function($) {
// default options
var defaults = {
    option1: "what ever",
    option2: "what ever"
};

// available methods
var methods = {
    method1: function(param1) {
        console.log(param1);
        /* ... */
    },
    method2: function(param1, param2) {
        console.log(param1);
        console.log(param2); // gives undefined
        /* ... */
    }
};

// Where magic happens
$.fn.pskChart = function(params) {
    if (methods[params] != undefined) {
        if (this.length > 0) {
            return $(this).each(function(i) {
                return methods[params].apply($(this), Array.prototype.slice.call(arguments, 1));
            });
        }
    } else {
        $.error("Method " + params + " doesn't exist for pskChart");
    }
}
})(jQuery);


$("#sample").pskChart("method1", "param1"); // will work
$("#sample").pskChart("method2", "param1", "param2"); // won't work

This code is working in case I provide only two parameters (method and another parameter), but won't work if I have more parameters

I understand that Array.prototype.slice.call(arguments, 1) returns only one object containing all the remaining arguments.

In the second example, method2 will be called with only one parameter that contains ["param1","param2"]


I would like to "split" this object in order to provide as many parameters I have.

I feel like methods[params].apply($(this), Array.prototype.slice.call(arguments, 1)); but I have no clue how to fix it.

Note that I could have an infinite (or at least big) number of parameters (in addition to the method, that will always be first). Playing with Array.slice would not be a great (nor proper) solution.

Upvotes: 0

Views: 133

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074138

I don't see why it would work even with just one parameter, as you're using the wrong arguments object.

Instead (see comments):

// Where magic happens
$.fn.pskChart = function(params) {
    var args; // **Change** We'll use this below
    if (methods[params] != undefined) {
        if (this.length > 0) {
            // **Change** Grab the arguments here, in the `pskChart` function
            args = Array.prototype.slice.call(arguments, 1);
            return $(this).each(function(i) {
                // **Change** Use them here; you can't use `arguments` here
                // because, it will be the arguments to this anonymouus
                // function, not the ones to `pskChart`
                return methods[params].apply($(this), args);
            });
        }
    } else {
        $.error("Method " + params + " doesn't exist for pskChart");
    }
}

Side note: params is a very strange name for an argument you're using as a method name. Perhaps methodName?

Side note 2: Rather than repeatedly looking up methods[params], consider using a variable. Large sets may benefit from the reduced work.

Side note 3: This line inside your each loop is almost certainly a mistake:

return methods[params].apply($(this), args);

That will return the return value of the method to jQuery's each code. jQuery's each code will completely ignore that vallue unless it's === false, in which case it will stop the each loop. Not at all likely to be what you meant that to do.

Side note 4: Your pskChart function, being a jQuery plugin, should return this unless it has a good reason for returning something else. Right now, the return value is chaotic: If the set has no elements, you return undefined (implicitly); if the set has objects, you return a new jQuery object, not this, because of this line:

return $(this).each(function(i) {

There's no reason for using $() there, this is already a jQuery set (which is why the previous line using this.length works).

Side note 5: You're missing a semicolon from the assignment statement (e.g., there should be one after the closing } on the function expression).

Recommendation:

// Where magic happens
$.fn.pskChart = function(methodName) {
    var args, method = methods[methodName];

    if (!method) {
        // Throws
        $.error("Method " + params + " doesn't exist for pskChart");
    }

    if (this.length > 0) {
        args = Array.prototype.slice.call(arguments, 1);
        this.each(function() {
            method.apply($(this), args);
        });
    }

    return this;
};

Upvotes: 3

Related Questions