13

I come from a Prototype JS background where OO Javascript is encouraged through the use of Class.create(). Now I am doing some JQuery work and I am trying to write some properly structured JQuery code where I can, for example, call the same object function from two different click event handlers.

Here is the code in Prototype:

document.observe("dom:loaded", function() {

    // create document
    APP.pageHelper = new APP.PageHelper();


});

// namespace our code
window.APP = {};

// my class
APP.PageHelper = Class.create({

  // automatically called
  initialize: function(name, sound) {
    this.myValue = "Foo";

    // attach event handlers, binding to 'this' object
    $("myButton").observe("click", this.displayMessage.bind(this))

  },

  displayMessage: function() {
    console.log("My value: " + this.myValue); // 'this' is the object not the clicked button!
  }

});

I am wondering how the following code can be replicated in JQuery where there is no way to bind a function call to the object it is called in, and 'this' is always the element clicked.

I have heard of a way to do it the Douglas Crockford 'module' pattern (http://www.yuiblog.com/blog/2007/06/12/module-pattern/) but I would love if someone could show me how you would implement the code above using JQuery and that pattern.

Thanks in advance.

Rob W
  • 341,306
  • 83
  • 791
  • 678
Ciaran Archer
  • 12,316
  • 9
  • 38
  • 55
  • 2
    Great question... I am a mootools guy myself, where you have the `Class` object and `bind` method to accomplish this pattern. In jQuery, `bind` means something else entirely! – Chris Baker May 05 '11 at 21:05
  • possible duplicate of [jQuery: Writing jquery in an object oriented way](http://stackoverflow.com/questions/2980354/jquery-writing-jquery-in-an-object-oriented-way) – Naftali May 05 '11 at 21:10
  • jQuery and OO are unrelated. If you really want to use Javascript OO, you won't use jQuery =) jQuery is not a 'OO build classes' framework; it's a DOM+events+animations shizzle framework. If you want to add events, shuffle a few html nodes and show dancing unicorns, don't do it OO style: do it simple and readable. – Rudie May 05 '11 at 21:38

6 Answers6

4

I roll my own objects based on this good article:

http://www.klauskomenda.com/code/javascript-programming-patterns/

I just choose whichever pattern makes sense for the project I'm working on. So like a quick example to do what you're asking would be:

$.myNamespace.myClass = function (options) {
    this.settings = $.extend({ ... defaults ... }, options);
    this.init();
};
$.myNamespace.myClass.prototype.settings = {
    someValue: 'default',
    someSelector: '#myButton'
};
$.myNamespace.myClass.prototype.init = function () {
    var self = this;
    $(self.settings.someSelector).click(function (event) {
        console.log(self.settings.someValue);
    });
};

You responded below that you knew about prototype but the syntax is a bit annoying. I think that's just a matter of being used to one syntax over another. I'm sure the Prototype library makes use of closures and .prototype just like I did above and like some other answers suggest below. In the end, just write syntax that you feel comfortable with. The suggestion to use Coffee Script is cool too - whatever floats your boat :)

Milimetric
  • 13,411
  • 4
  • 44
  • 56
  • sorry, I think I read too quickly. I wrote some quick sample code above. (I assumed my usual jQuery namespacing trick: http://stackoverflow.com/questions/527089/is-it-possible-to-create-a-namespace-in-jquery) – Milimetric May 06 '11 at 02:24
3

You can absolutely bind an event to something other then the dom element. Just use $.proxy.

Description:

Takes a function and returns a new one that will always have a particular context. version added: 1.4

 /**
  * @param function - The function whose context will be changed.
  * @param context - The object to which the context (this) of the function should be set.
  */
jQuery.proxy( function, context )

This method is most useful for attaching event handlers to an element where the context is pointing back to a different object. Additionally, jQuery makes sure that even if you bind the function returned from jQuery.proxy() it will still unbind the correct function if passed the original.

Community
  • 1
  • 1
Gabriel
  • 18,322
  • 2
  • 37
  • 44
  • 1
    Super, this is really what I needed. Great to know that exists and avoid the `bind()` confusion. I wrote up a quick explanation so that others can see the original example in my question ported to JQuery: http://flydillonfly.wordpress.com/2011/05/06/writing-oo-javascript-using-jquery/ – Ciaran Archer May 06 '11 at 07:08
  • Thanks for the sharing the link. I am happy I was able to help. – Gabriel May 07 '11 at 01:42
1

If you are looking for a somewhat similar OOP structure for JQuery, you might try http://code.google.com/p/jquery-klass/

It's what I use.

shellster
  • 1,091
  • 1
  • 10
  • 21
1

You don't need Class.create() to write classes in javascript.

APP.PageHelper = function(name, sound) { // this is the constructor
    this.myValue = "Foo";
    // attach event handlers, binding to 'this' object
    $('#myButton').click($.proxy(this.displayMessage, this)); // use $.proxy instead of `bind`
}
APP.PageHelper.prototype = { // define more prototype functions here
    displayMessage: function() {
        console.log("My value: " + this.myValue); // 'this' is the object not the clicked button!
    }
};

Now for more complicated classes with inheritance I use John Resig's simple class inheritance.

I also separate classes into files, wrapped with a closure. This would be PageHelper.js:

;!!window['APP'] && (function (NS, $) {
    NS.PageHelper = Class.extend({ // see link above
        // functions
        init: function () { // constructor

        },
        displayMessage: function() { 

        }
    });
})(window['APP'], jQuery);
Josiah Ruddell
  • 29,697
  • 8
  • 65
  • 67
  • I am aware of the regular way to use write classes using `.prototype`. You don't *need* `Class.create()` but if you are using Prototype it is nice and convenient. – Ciaran Archer May 05 '11 at 22:15
0

I find writing OO code in CoffeeScript to be much more pleasant than Class.create() or lower level prototype stuff. Check out the section on function binding.

Detect
  • 2,049
  • 1
  • 12
  • 21
0

I think the best jQuery Class implementation is from John Resig's blog (http://ejohn.org/blog/simple-javascript-inheritance/). I highly recommend it; it's very similar to Prototype JS.

I wrote a library on top of it to make OO design easy within jQuery ( https://github.com/arturnt/brickjs ). For example, in order to do what you are doing there you can do the following.

Comp.APP = {};
Comp.APP.PageHelper = Comp.extend({
    init: function(e) {
        this._super(e);
        this.myValue = "foo";
    },
    "#myButton click": function() {
        console.log(this.myValue); //prints
    }
});

Art
  • 5,864
  • 3
  • 30
  • 32