Object-oriented plugins?
|
View:
New views
7 Messages
—
Rating Filter:
Alert me
|
|
|
Object-oriented plugins?Does anyone know of a good example of an object-oriented plugin for jQuery?
The reason I ask is that the jQuery convention is to return this at the end of the plugin to allow for chaining. While that's great for simple plugins, some of my advanced plugins instantiate object that I would like to access at various points in my script. From the looks of it, jQuery's "tabs" plugin seems to use an object stored "somewhere" (perhaps in the element). But to invoke methods on that object, you have to call the plugin again and pass it a string as its first parameter: http://docs.jquery.com/UI/Tabs/tabs#.22enable.22index jQuery#tabs( "add", url, label, [index] ) To be honest, this seems a little awkward for me. This means I would have to write my plugin to check the first parameter to see if it's a string or an object, and if it's a string I then would have to make a switch to call the approriate method based on the string value. I would much rather be able to access the tabs instance directly: var tabs = $('#tabbed').tabs(); // tabs is instance of jQueryTabs tabs.add(url, label); // accessing instance directly But if tabs acted like that, it would break chaining. $('#tabbed').tabs().hide(); // This would error Is there another way to create object-oriented plugins, while still following the jQuery conventions? Thanks! -Hector |
|
|
Re: Object-oriented plugins?> To be honest, this seems a little awkward for me. This means I would have to > write my plugin to check the first parameter to see if it's a string or an > object, and if it's a string I then would have to make a switch to call the > approriate method based on the string value. You don't need a switch, you can call a method like this: object['method_name'](); and also you can store the instance with $.data This is what UI's widget factory was built for: http://docs.jquery.com/UI/Developer_Guide As for UI widgets you can call the method directly with $.data: $("#tabbed").tabs(); $("#tabbed").data('tabs').add('test.html', 'new tab', 4); But I'm not sure if this would be the encouraged way of using plugins, actually I haven't heard about any convention you could follow when writing an OO plugin. This questions comes up from time to time and it seems it's up to you to pick a pattern. On Nov 23, 4:03 am, "Hector Virgen" <djvir...@...> wrote: > Does anyone know of a good example of an object-oriented plugin for jQuery? > > The reason I ask is that the jQuery convention is to return *this* at the > end of the plugin to allow for chaining. While that's great for simple > plugins, some of my advanced plugins instantiate object that I would like to > access at various points in my script. > > From the looks of it, jQuery's "tabs" plugin seems to use an object stored > "somewhere" (perhaps in the element). But to invoke methods on that object, > you have to call the plugin again and pass it a string as its first > parameter: > > http://docs.jquery.com/UI/Tabs/tabs#.22enable.22index > jQuery#tabs( "add", url, label, [index] ) > > To be honest, this seems a little awkward for me. This means I would have to > write my plugin to check the first parameter to see if it's a string or an > object, and if it's a string I then would have to make a switch to call the > approriate method based on the string value. > > I would much rather be able to access the tabs instance directly: > > var tabs = $('#tabbed').tabs(); // tabs is instance of jQueryTabs > tabs.add(url, label); // accessing instance directly > > But if tabs acted like that, it would break chaining. > > $('#tabbed').tabs().hide(); // This would error > > Is there another way to create object-oriented plugins, while still > following the jQuery conventions? > > Thanks! > > -Hector |
|
|
Re: Object-oriented plugins?Providing the method name as the first parameter is a bit awkward, perhaps looking at the alternatives would help: Add namespaces to jQuery. This isn't very jQuery-like. Example: $ (el).tabs.add(url, label).show(); Add a new jQuery method for every plugin instance method. This pollutes the jQuery namespace, so this should only be done when it really makes sense. Example: $(el).addTab(url, label); Use events. You can bind custom events in a namespace and then have users interact with your plugin by triggering those events. Example: $ (el).trigger('add.tabs', url, label); There may be other approaches as well. The jQuery UI approach allows plugins to expose as many methods as they want while only using one method in the jQuery namespace. |
|
|
Re: Object-oriented plugins?I've been thinking about this over the weekend and came up with a way to write class-based plugins while still following the jQuery convention. Maybe someone else has done this before but I couldn't find any documentation on this subject.
The idea is to extend the base jQuery object with the javascript class, and then extend jQuery.fn with a simple method that does nothing but instantiate the class and return "this". The nice thing about this approach is that you can still make chainable plugins without polluting the jQuery.fn namespace with a ton of methods. $('#mydiv').myplugin().show();
But if you need access to the object, you can use the "new" construct. var myplugin = new $.MyPlugin($('#mydiv')); myplugin.doSomething(); Here is an example plugin that just alerts some text when the selected elements are clicked. But, if you create the plugin object manually with the "new" construct, you can change the message or invoke the alert without the click: (function($){ var Alerter = function(selector, options) {
var obj = this; this.settings = {
message: 'no message' };
$.extend(this.settings, options); selector.click(function() { obj.alert.call(obj);
}); } Alerter.prototype.alert = function() { alert('Alerter said: ' + this.settings.message);
} Alerter.prototype.message = function(message)
{ this.settings.message = message; return this;
} $.extend({
Alerter: Alerter }); $.fn.extend({ alerter: function(options) {
var alerter = new $.Alerter(this, options); return this; }
}); })(jQuery); // Usage as jQuery plugin $('#mydiv').alerter({ message: 'foo' }); // Usage as object var alerter = new $.Alerter($('#anotherdiv'), { message: 'bar' }); // As an object, you can call methods on it easily alerter.message('new message'); alerter.alert(); // alerts "Alerter said: new message"
Any thoughts on this approach? -Hector On Sun, Nov 23, 2008 at 5:15 AM, Scott González <scott.gonzalez@...> wrote:
|
|
|
Re: Object-oriented plugins?I personally use the same approach in the Translate plugin (maybe I should have told you that before :), but with that you don't need the 'new' keyword: $.translate() returns a new object (it's a bit similar to $.ajax or jQuery itself, you don't need 'new' there either). http://code.google.com/p/jquery-translate/ With Translate you can only control the behaviour through the options when using the jQuery method (though the object is available in callback functions), but in your case I think you can still consider letting the first variable call a method: $.fn.alerter = function(a){ if(typeof a!="string") { var alerter = new $.Alerter(this, a); $(this).data("alerter", alerter); //store the instance } else { var instance = $(this).data("alerter"); //get the instance instance[a].apply(instance, $.makeArray(arguments).slice(1) ); // call method } return this; } I don't want to push this but it's really not a lot of code for a shorthand, as you don't need to deal with the instances in your code beacause they're handled by the plugin and you can call methods without breaking a chain, but it really depends on what you want the plugin to do. Some other discussions related to this topic if you're interested: http://groups.google.com/group/jquery-en/browse_thread/thread/9dc9be1cc298cbdd http://groups.google.com/group/jquery-dev/browse_thread/thread/48400f696b85a7cb http://groups.google.com/group/jquery-dev/browse_thread/thread/b2f784b7575456dc/0cd276379f8a2f7d?show_docid=0cd276379f8a2f7d http://groups.google.com/group/jquery-dev/browse_thread/thread/6c02b9b939c96bdb/5f244e161b9c1346?show_docid=5f244e161b9c1346 On Nov 26, 7:16 pm, "Hector Virgen" <djvir...@...> wrote: > I've been thinking about this over the weekend and came up with a way to > write class-based plugins while still following the jQuery convention. Maybe > someone else has done this before but I couldn't find any documentation on > this subject. > The idea is to extend the base jQuery object with the javascript class, and > then extend jQuery.fn with a simple method that does nothing but instantiate > the class and return "this". > > The nice thing about this approach is that you can still make chainable > plugins without polluting the jQuery.fn namespace with a ton of methods. > > $('#mydiv').myplugin().show(); > > But if you need access to the object, you can use the "new" construct. > > var myplugin = new $.MyPlugin($('#mydiv')); > myplugin.doSomething(); > > Here is an example plugin that just alerts some text when the selected > elements are clicked. But, if you create the plugin object manually with the > "new" construct, you can change the message or invoke the alert without the > click: > > (function($){ > var Alerter = function(selector, options) > { > var obj = this; > this.settings = { > message: 'no message'}; > > $.extend(this.settings, options); > selector.click(function() > { > obj.alert.call(obj);}); > } > > Alerter.prototype.alert = function() > { > alert('Alerter said: ' + this.settings.message);} > > Alerter.prototype.message = function(message) > { > this.settings.message = message; > return this;} > > $.extend({ > Alerter: Alerter}); > > $.fn.extend({ > alerter: function(options) > { > var alerter = new $.Alerter(this, options); > return this; > > } > }); > })(jQuery); > > // Usage as jQuery plugin > $('#mydiv').alerter({ > message: 'foo' > > }); > > // Usage as object > var alerter = new $.Alerter($('#anotherdiv'), { > message: 'bar' > > }); > > // As an object, you can call methods on it easily > alerter.message('new message'); > alerter.alert(); // alerts "Alerter said: new message" > > Any thoughts on this approach? > > -Hector > > On Sun, Nov 23, 2008 at 5:15 AM, Scott González <scott.gonza...@...>wrote: > > > > > Providing the method name as the first parameter is a bit awkward, > > perhaps looking at the alternatives would help: > > > Add namespaces to jQuery. This isn't very jQuery-like. Example: $ > > (el).tabs.add(url, label).show(); > > > Add a new jQuery method for every plugin instance method. This > > pollutes the jQuery namespace, so this should only be done when it > > really makes sense. Example: $(el).addTab(url, label); > > > Use events. You can bind custom events in a namespace and then have > > users interact with your plugin by triggering those events. Example: $ > > (el).trigger('add.tabs', url, label); > > > There may be other approaches as well. > > > The jQuery UI approach allows plugins to expose as many methods as > > they want while only using one method in the jQuery namespace. |
|
|
Re: Object-oriented plugins?I've been writing a lot of jQuery plugins for internal use that use an OO and prototypal approach. I have a basic class that i use for all plugins that provides some basic methods (like storing the instance in the .data() of the element and fires the internal methods of the subclass, and then i attach a basic jQuery plugin functionality to start it all up. I've found it rather enjoyable to work with for creating and working with objects with a lot of methods...and it keeps the jQuery namespace clean app.Toolbox = function(tool) { function Toolbox() {} Toolbox.prototype = $.extend({ flag:function() { app.flags[tool.name] = true; }, unflag:function() { delete app.flags[tool.name]; }, initTool:function() { if (tool.flags) { if (app.flags[tool.name]) { alert("You can only launch one "+tool.description+" at a time."); return false; } else { this.flag(); } } tool.$el.data(tool.name,this); return this.init(); }, takeDown:function() { tool.destroy.call(this); tool.$el.removeData(tool.name); tool.flags && this.unflag(); } },tool); return new Toolbox().initTool(); }; jQuery.fn.columnMasterEditor = function() { return this.each(function() { var $a = $("<a href='#' class='masterEditLink' title='Update entire column...'/>"); $a .tooltip(app.defaults.tooltip) .prependTo(this) .bind("click.columnMasterEditor",function(e) { new app.Toolbox.ColumnMasterEditor($a,e); return false; }); }); }; this is just a pattern i have developed for myself but if anyone has feedback on it please do share... --adam On Nov 26, 3:41 pm, Balazs Endresz <balazs.endr...@...> wrote: > I personally use the same approach in the Translate plugin (maybe I > should have told you that before :), but with that you don't need the > 'new' keyword: $.translate() returns a new object (it's a bit similar > to $.ajax or jQuery itself, you don't need 'new' there either).http://code.google.com/p/jquery-translate/ > > With Translate you can only control the behaviour through the options > when using the jQuery method (though the object is available in > callback functions), but in your case I think you can still consider > letting the first variable call a method: > > $.fn.alerter = function(a){ > if(typeof a!="string") { > var alerter = new $.Alerter(this, a); > $(this).data("alerter", alerter); //store the instance > } else { > var instance = $(this).data("alerter"); //get the instance > instance[a].apply(instance, $.makeArray(arguments).slice(1) ); // > call method > } > return this; > > } > > I don't want to push this but it's really not a lot of code for a > shorthand, as you don't need to deal with the instances in your code > beacause they're handled by the plugin and you can call methods > without breaking a chain, but it really depends on what you want the > plugin to do. > > Some other discussions related to this topic if you're interested:http://groups.google.com/group/jquery-en/browse_thread/thread/9dc9be1...http://groups.google.com/group/jquery-dev/browse_thread/thread/48400f...http://groups.google.com/group/jquery-dev/browse_thread/thread/b2f784...http://groups.google.com/group/jquery-dev/browse_thread/thread/6c02b9... > > On Nov 26, 7:16 pm, "Hector Virgen" <djvir...@...> wrote: > > > I've been thinking about this over the weekend and came up with a way to > > write class-based plugins while still following the jQuery convention. Maybe > > someone else has done this before but I couldn't find any documentation on > > this subject. > > The idea is to extend the base jQuery object with the javascript class, and > > then extend jQuery.fn with a simple method that does nothing but instantiate > > the class and return "this". > > > The nice thing about this approach is that you can still make chainable > > plugins without polluting the jQuery.fn namespace with a ton of methods. > > > $('#mydiv').myplugin().show(); > > > But if you need access to the object, you can use the "new" construct. > > > var myplugin = new $.MyPlugin($('#mydiv')); > > myplugin.doSomething(); > > > Here is an example plugin that just alerts some text when the selected > > elements are clicked. But, if you create the plugin object manually with the > > "new" construct, you can change the message or invoke the alert without the > > click: > > > (function($){ > > var Alerter = function(selector, options) > > { > > var obj = this; > > this.settings = { > > message: 'no message'}; > > > $.extend(this.settings, options); > > selector.click(function() > > { > > obj.alert.call(obj);}); > > } > > > Alerter.prototype.alert = function() > > { > > alert('Alerter said: ' + this.settings.message);} > > > Alerter.prototype.message = function(message) > > { > > this.settings.message = message; > > return this;} > > > $.extend({ > > Alerter: Alerter}); > > > $.fn.extend({ > > alerter: function(options) > > { > > var alerter = new $.Alerter(this, options); > > return this; > > > } > > }); > > })(jQuery); > > > // Usage as jQuery plugin > > $('#mydiv').alerter({ > > message: 'foo' > > > }); > > > // Usage as object > > var alerter = new $.Alerter($('#anotherdiv'), { > > message: 'bar' > > > }); > > > // As an object, you can call methods on it easily > > alerter.message('new message'); > > alerter.alert(); // alerts "Alerter said: new message" > > > Any thoughts on this approach? > > > -Hector > > > On Sun, Nov 23, 2008 at 5:15 AM, Scott González <scott.gonza...@...>wrote: > > > > Providing the method name as the first parameter is a bit awkward, > > > perhaps looking at the alternatives would help: > > > > Add namespaces to jQuery. This isn't very jQuery-like. Example: $ > > > (el).tabs.add(url, label).show(); > > > > Add a new jQuery method for every plugin instance method. This > > > pollutes the jQuery namespace, so this should only be done when it > > > really makes sense. Example: $(el).addTab(url, label); > > > > Use events. You can bind custom events in a namespace and then have > > > users interact with your plugin by triggering those events. Example: $ > > > (el).trigger('add.tabs', url, label); > > > > There may be other approaches as well. > > > > The jQuery UI approach allows plugins to expose as many methods as > > > they want while only using one method in the jQuery namespace. |
|
|
Re: Object-oriented plugins?On Nov 26, 10:27 pm, ajpiano <ajpi...@...> wrote: > > this is just a pattern i have developed for myself but if anyone has > feedback on it please do share... > Can you show an example of how such a class would be used? Im struggling to understand the benefit of it, although Im sure there is one Thanks |
| Free embeddable forum powered by Nabble | Forum Help |