Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clarify to me this javascript pattern

I'm interested on how is realized the JavaScript pattern used, for example, in jQuery UI dialog:

$.dialog('mydialod').dialog('close');

ie I can't get how to reference back a constructor function after I created it in a jQuery compliant fashion.

EDIT

Just to clarify: what is really obscure to me is how I can have somewhere

$('#mydlg').dialog();

and then somewhere else

 $('#mydlg').dialog("somecommand");

that even in absolutely different places seems to point back to the original instance. I think, it is somehow related with this (jquery.ui.widgets.js ),

// create selector for plugin
    $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
        return !!$.data( elem, fullName );
    };

but really I'm too green in javascript / jquery to get what's happening.

like image 694
Felice Pollano Avatar asked Dec 21 '22 05:12

Felice Pollano


2 Answers

I'm not sure how jQuery UI does it (you'd have to look at the source), but here's a way to do this https://gist.github.com/elclanrs/5668357

The advantage of using this approach is that you keep all your methods private instead of in the prototype by using a closure; a module pattern in this case.

Edit: Aight, got it. This is how I got it to work. This I'm calling the "Advanced jQuery Boilerplate". I added the methods to the prototype, I don't think it really makes a difference to keep them outside, and makes it easier to call methods within methods with this.method():

(function($) {

  var _pluginName = 'myplugin'
    , _defaults = {

      };

  function Plugin(el, options) {
    this.opts = $.extend({}, _defaults, options);
    this.el = el;
    this._init();
  }

  Plugin.prototype = {
    _init: function() {
      return this;
    },

    method: function(str) {
      console.log(str);
      return this;
    }
  };

  Plugin.prototype[_pluginName] = function(method) {
    if (!method) return this._init();
    try { return this[method].apply(this, [].slice.call(arguments, 1)); }
    catch(e) {} finally { return this; }
  };

  $.fn[_pluginName] = function() {
    var args = arguments;

    return this.each(function() {
      var instance = $.data(this, 'plugin_'+ _pluginName);

      if (typeof args[0] == 'object') {
        return $.data(this, 'plugin_'+ _pluginName, new Plugin(this, args[0]));
      }
      return instance[_pluginName].apply(instance, args);
    });
  };

}(jQuery));

Now I have two divs:

<div></div>
<div id="mydiv"></div>

And I can use the plugin like:

$('div').dialog({ n: 69 }); // initialize both divs

console.log($('#mydiv').dialog('method', 'hello world'));
//=^ prints "hello world" and returns instance

console.log($('#mydiv').data('plugin_dialog').opts.n); //=> 69

It's basically storing the instance of the plugin in data to be able to restore the options since this info is attached to the element. It's similar to how jQuery Boilerplate works.

like image 182
13 revs Avatar answered Dec 22 '22 19:12

13 revs


This is called 'chaining pattern'. Basic idea is that object methods return constructed instance, look at simplified example:

function Dialog (){
    this.open = function(){
        console.log('open dialog');
        return this;
    }

    this.close = function(){
        console.log('close dialog');
        return this;
    }

}

var d = new Dialog();
d.open().close();

Note 'return this' statement in every method.

like image 23
Pavel Zastavnitskiy Avatar answered Dec 22 '22 18:12

Pavel Zastavnitskiy