MotionGrafika
MotionGrafika

Reputation: 1131

jQuery Plugin Namespace

How do I create a jQuery plugin so that I can use namespaces in my plugin ?

$("#id1").amtec.foo1();
$("#id1").amtec.foo2();

None of these seem to work.

(function($) {
    var amtec = {
        $.fn.foo1 : function(){ return this.each(function(){}); },
        $.fn.foo2 : function(){ return this.each(function(){}); }
        };

    })(jQuery);
(function($) {
    $.fn.amtec = function(){
        var foo1 = function(){ return this.each(function(){}); };
        var foo2 = function(){ return this.each(function(){}); };
        }
    })(jQuery);

Upvotes: 26

Views: 12683

Answers (5)

Milosz
Milosz

Reputation: 3074

I know I'm almost three years late to the party, but hopefully future readers of this question can benefit from my answer. The answer by GSto looks great from a jQuery plugin design standpoint, but has one small issue: calling mynamespace() clobbers the returned jQuery instance with new methods. Here is an example of that being an issue:

$myDiv = $('.mydiv');
$myDiv.mynamespace().height(); // this will be `height' from mynamespace
$myDiv.height();               // this will STILL be `height' from mynamespace
                               //   because it has overwritten $myDiv.height

The chosen answer does not have this issue because there amtec() is not a jQuery instance and is instead an object that calls its methods with the jQuery instance as context. I have taken concepts from both answers and written the namespace plugin below:

(function($) {
  $.namespace = function(namespaceName, closures) {

    if ($.fn[namespaceName] === undefined) {
      $.fn[namespaceName] = function executor(context) {
        if (this instanceof executor) {
          this.__context__ = context;
        }
        else {
          return new executor(this);
        }
      };
    }

    $.each(closures, function(closureName, closure) {
      $.fn[namespaceName].prototype[closureName] = function() {
        return closure.apply(this.__context__, arguments);
      };
    });

  };
})(jQuery);

Example usage:

$.namespace('milosz', {
    redify: function() {
        $(this).css('color', '#ff0000');
    },
    greenify: function() {
        $(this).css('color', '#00ff00');
    }
});

$.namespace('milosz', {
    blueify: function() {
        $(this).css('color', '#0000ff');
    }
});

$('.mydiv').milosz().redify(); // The HTML elements with class `mydiv' are now red

The code uses some pretty low-level details of JavaScript that are well-explained by John Resig's Advanced JavaScript tutorial, but loosely speaking what is happening in the example is this:

When milosz (internally $.fn[namespaceName]) is called, this points to the jQuery instance returned by $('.mydiv'). Hence, the if statement falls through to the else block and the constructor version of milosz is called (referred-to internally as executor for reasons that are about to become apparent). The constructor is passed a single parameter: this, a pointer to the jQuery the instance that is going to be the execution context for all members of the milosz namespace. We enter back into the if statement, this time executing the first block, wherein the passed-in jQuery instance is stored in a member variable called __context__ (which hopefully has a low chance of being overwritten). The constructed object is returned, complete with a reference to the original jQuery instance and any wrappers added to its prototype by invocations of $.namespace. These wrappers simply execute the methods passed into the milosz namespace with the original jQuery object as context, as happens when redify is executed.

Bah, I know it's a mouthful, anyway the point is it works like the accepted answer but looks like the jQueryish answer, which to me is the best of both worlds.

Upvotes: 16

Md. Alim Ul Karim
Md. Alim Ul Karim

Reputation: 2432

 $.cg = {
  foo1: function(weq){
      return console.log(weq);
  },
  foo2: function(rw){
      return console.log(rw);
 }
}; 
$.cg = { // will result in error because $.cg is already declared above

  foo4: function(rw){ // will result in error
      return console.log(rw); // will result in error
 } // will result in error
}; // will result in error

$.cg.foo3 = function(weq){ //to add anything new to $.cg , you have to do it this way.
      return console.log(weq);
  }

$.cg.foo1("12");
$.cg.foo2("22"); //works fine.
$.cg.foo3("112"); //works fine.

Upvotes: 1

Adam Biggs
Adam Biggs

Reputation: 3663

I know it's an old question... But why write all this extra code when you can just replace . with _?

$.fn.amtec_foo1 = function(){ return this.each(function(){}); }
$.fn.amtec_foo2 = function(){ return this.each(function(){}); }

Better yet, give your plugin a name that's original & project agnostic.

$.fn.fooize = function(){ return this.html('Element has been Fooized!'); }

Upvotes: 2

Alex Gyoshev
Alex Gyoshev

Reputation: 11977

(function($) {
    $.fn.amtec = function () {
        var jq = this;
        return {
            foo1: function(){
                return jq.each(function(){});
            },

            foo2: function(){
                return jq.each(function(){});
           }
       }
    };
})(jQuery);

Upvotes: 21

GSto
GSto

Reputation: 42350

(function($){
  $.namespace = function(ns, functions){
    $.fn[ns] = function() {return this.extend(functions)};
  };
  $.namespace('$', $.fn); // the default namespace
})(jQuery);

So now you can have a plugin:

$.fn.func = function(){alert('plugin'); return this'};

and create plugins in a namespace:

$.namespace ('mynamespace', {
  func: function() {alert('namespaced plugin'); return this;},
  otherfunc: function() {return this.css('color', 'yellow');}
});

And if you do

$('div').func(); // alerts 'plugin' -- no namespace

But

$('div').mynamespace().func(); // alerts 'namespaced plugin'

And

$('div').mynamespace().func().$().func(); // alerts 'namespaced

plugin', then resets to the normal jquery and alerts 'plugin'

Upvotes: 3

Related Questions