Martin
Martin

Reputation: 4330

Initialize Mootools class with parameters from array

I have a Mootools class:

var Foo = new Class({
    initialize: function(param1, param2) {
        // do stuff
    }
});

The values to initialize Foo with are in an array:

a = ['value1', 'value2'];

How can I use the values from a to initialize an instance of Foo?

Upvotes: 0

Views: 393

Answers (2)

creethy
creethy

Reputation: 36

There is no direct way of calling a constructor with an array of arguments to be expanded, like you do it with Function.apply.

If you create a new instance of your class with new Foo(), MooTools calls the constructor (initialize) implicitly passing it the arguments you called Foo() with. However, initialize is still present as a method of the instance, so you could simply call it "again" like so:

var myFoo = new Foo();
myFoo.initialize.apply(myFoo, ['value1', 'value2']);

But this is really bad practice, because a constructor is normally not meant to be called twice and chances are that you run into problems.

Another way is to create the instance without letting MooTools call the constructor. First you need a plain instance and then call initialize as a method of the instance. This is rather hackish, but could be realized like this:

var Foo = new Class({
    initialize: function(param1, param2) {
        this.param1 = param1;
        this.param2 = param2;
    },
    getParams: function() {
        console.log(this.param1 + ', ' + this.param2);
    }
});

Class.createInstance = function(klass, args) {
    klass.$prototyping = true;
    var inst = new klass();
    klass.$prototyping = false;
    inst.initialize.apply(inst, args);
    return inst;
}

var myFoo = Class.createInstance(Foo, ['a', 'b']);

// returns "a, b"
myFoo.getParams();

$prototyping is the switch for MooTools to not call the constructor.

Upvotes: 2

Dimitar Christoff
Dimitar Christoff

Reputation: 26165

I'd go with extending the proto of the class so it does not care (see Felix' answer).

var Foo = new Class({
    initialize: function(param1, param2) {
        console.log(param1, param2);
    }
});

(function(){
    var oldFoo = Foo.prototype.initialize;
    Foo.implement({
        initialize: function(){
            var args = typeOf(arguments[0]) == 'array' ? arguments[0] : arguments;
            return oldFoo.apply(this, args);
        }
    });
}());


new Foo(['one', 'two']); // one two
new Foo('three', 'four'); // three four

It involves less hacking and is probably easier to understand/maintain than creating special constructor abstractions.

if you can, you can even do

var Foo2 = new Class({
     Extends: Foo,
     initialize: function () {
         var args = typeOf(arguments[0]) == 'array' ? arguments[0] : arguments;
         this.parent.apply(this, args);
     }
});

new Foo2(['one', 'two']);
new Foo2('three', 'four');

Thus, making a very clear abstraction without modifying the parent proto and expectation - and keeping pesky SOLID principles assholes happy :D

Upvotes: 3

Related Questions