Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I emulate the Jquery UI API?

I've written basic jQuery plugins before, but I'm struggling to get my head around something more complex. I'm looking to emulate the API of jQuery UI, which works like this:

$('#mydiv').sortable({name: 'value'}); // constructor, options
$('#mydiv').sortable("serialize"); // call a method, with existing options
$('#mydiv').sortable('option', 'axis', 'x'); // get an existing option

I've tried the following:

(function($){
    $.fn.myPlugin = function(cmd){
        var config = {
            default: 'defaultVal'
        };

        if(typeof cmd === 'object'){
            $.extend(config, cmd);
        }

        function _foo(){
            console.log(config.default);
        }

        if(cmd==='foo'){
            return _foo();
        }

        this.each(function(){
            // do default stuff
        });
    }
})(jQuery);

$('#myElement').myPlugin({default: 'newVal'});
$('#myElement').myPlugin('foo');

What I would like to see here is 'newval' being logged, but I'm seeing 'defaultVal' instead; the plugin is being called and started from scratch every time I call .myPlugin() on the element.

I've also tried using _foo.call(this) and some other variants. No joy.

In a way, I understand why this is happening, but I know that it must be possible to do it the same way as jQuery UI. I just can't see how!

(I appreciate that jQuery UI uses the widget factory to handle all of this, but I don't want to make that a requirement for the plugin.)

like image 508
John McCollum Avatar asked Feb 22 '10 22:02

John McCollum


2 Answers

Perhaps what you want is this...

(function($){

    var config = {
        default: 'defaultVal'
    };

    $.fn.myPlugin = function(cmd){

        if(typeof cmd === 'object'){
            $.extend(config, cmd);
        }

        function _foo(){
            console.log(config.default);
        }

        if(cmd==='foo'){
            return _foo();
        }

        this.each(function(){
            // do default stuff
        });
    }
})(jQuery);

$('#myElement').myPlugin({default: 'newVal'});
$('#myElement').myPlugin('foo');

Move the config variable outside the myPlugin function. This change will cause config to be initialized only once: when your plugin function is created.

like image 95
Drew Wills Avatar answered Sep 23 '22 17:09

Drew Wills


You're declaring config during the function call rather than as a closure used by it. Try this:

(function($){
    var config = {
        default: 'defaultVal'
    };
    $.fn.myPlugin = function(cmd){

        if(typeof cmd === 'object'){
            $.extend(config, cmd);
        }

        function _foo(){
            console.log(config.default);
        }

        if(cmd==='foo'){
            return _foo();
        }

        this.each(function(){
            // do default stuff
        });
    }
})(jQuery);

$('#myElement').myPlugin({default: 'newVal'});
$('#myElement').myPlugin('foo');

In addition, you could look into the jQuery data API for caching data, especially if you aren't going to have just one instance per page.

like image 35
NVRAM Avatar answered Sep 23 '22 17:09

NVRAM