views:

98

answers:

3

I have this code:

var myWidget = $('#myWidget');

and calls like this elsewhere:

myWidget.hide();
myWidget.slideToggle();

These work of course because jQuery adds these methods.

Now, let's say I'm doing some refactoring to make myWidget a proper object with its own custom methods and state:

var myWidget = (function() {
    // private stuff
    var actualJQueryObject = $('#myWidget');
    return {
        publicMethod: function() {...},
        // MAGIC!
    }
})()

but I want to have all the calls that expect a jQuery object, which are all around my code, to still work even though myWidget is no longer a jQuery object, because myWidget knows how to delegate these calls to actualJQueryObject.

Is this possible?

A: 

One option is using the original jquery object as a prototype.

function wrap(jqObject) {
    function MyNewType() {
        this.changeFontSize = function(a) { 
            this.css({fontSize : this.size});
        };
    }
    MyNewType.prototype = jqObject;
    return new MyNewType;
}
var obj = wrap($('#someitem'));
obj.size = 50;        // obj.size
obj.changeFontSize(); // obj.changeFontSize
obj.hide();           // $.hide
obj.fadeIn("slow");   // $.fadeIn
Jimmy
+2  A: 

You could also extend your jQuery object, with another object that has your custom methods:

var myWidget = function() {
    // private stuff
    var actualJQueryObject = $('#myWidget');

    var extensionMethods = {
        publicMethod: function() { alert('public method!'); }  
    }
    return $.extend(actualJQueryObject, extensionMethods);
}();

Just be careful with the name of your extension methods, to not clash with any other jQuery defined function.

You can try the above snippet here.

CMS
Beautiful, thank you. I knew there must have been some really basic way to do what I wanted with inheritance.
lawrence
Check my function i listed below just in case you need multiple namespaces.
Tres
A: 

I've written a plugin that might help you. It's basically a plugin for writing plugins. This dev group post explains it and has some code samples:

http://groups.google.com/group/jquery-dev/browse_thread/thread/664cb89b43ccb92c/72cf730045d4333a?hl=en&q=structure+plugin+authoring#72cf730045d4333a

And the source is here:

http://code.google.com/p/jquery-plugin-dev/source/browse/trunk/jquery.plugin.js

EDIT:

I created a function that has similar functionality to that plugin:

jQuerify = function(fn) {
    function plugin() {
     var instantiate = false;

     // check to see if it has any prototyped methods (we only need one iteration to do this)
     for (var i in construct.prototype) {
      instantiate = true;

      break;
     }

     // if there are prototyped methods, return an instance (since an instance's return value won't vary)
     // otherwise just call it using apply so the return value can vary
     return instantiate
      ? new construct(this, arguments)
      : construct(this, arguments);
    }

    function construct(parent, args) {
     // 'this' will not mimic jQuery unless given the length property
     this.length   = 0;
     this.selector = parent.selector;
     this.context  = parent.context;

     // mimic 'this' in jQuery, but for the plugin namespace
     Array.prototype.push.apply(this, $.makeArray(parent));

     // return the constructors return value
     // should be 'this' if you want to chain the new namespace
     return fn.apply(this, arguments);
    }

    // copy all static properties and methods
    for (var i in fn) {
     plugin[i] = fn[i];
    }

    // allow .fn and copy all instance properties and methods; the last part is for IE
    plugin.fn = construct.prototype = plugin.prototype = fn.prototype;

    return plugin;
}

This allows you to add custom objects to jQuery as a plugin while using 'this' to refer to the selected objects and also allows you to have an unlimited depth to your namespace:

function test1() {
    return this;
}
test1.prototype.getHtml1 = function() {
    return $(this).html();
}

function test2() {
    return this;
}
test2.prototype.getHtml2 = function() {
    return $(this).html();
}

function test3() {
    return this;
}
test3.prototype.getHtml3 = function() {
    return $(this).html();
}

jQuery.fn.test1                   = jQuerify(test1);
jQuery.fn.test1.fn.test2          = jQuerify(test2);
jQuery.fn.test1.fn.test2.fn.test3 = jQuerify(test3);

jQuery(function($) {

    alert($('body').test1().getHtml1());
    alert($('body').test1().test2().getHtml2());
    alert($('body').test1().test2().test3().getHtml3());

});
Tres