Way to extend Marionette.js view classes - javascript

I need to extend marionette.js classes with some functionality I'd like to have in all classes I create in my app.
What I currently do is to save original method of Marionette and to override it with my own method, calling to original from inside overridden.
For instance:
(function() {
var oldMarionetteItemViewConstructor = Marionette.ItemView.prototype.constructor;
Marionette.ItemView.prototype.constructor = function() {
// Some custom stuff I want to have here
.....
// Call to original constructor
return oldMarionetteItemViewConstructor.call(this, arguments);
}
})();
It seems some hacky and I wonder if there better way?

Marionette hoists the Backbone.View.extend() method (which itself is actually hoisted from Underscore.js) so all you have to do is:
var MyFancyView = Marionette.ItemView.extend({
//define your custom stuff here
});
var MyExtendedView = MyFancyView.extend({
//This view picks up the same props/methods form MyFancyView
});
You're pattern works, but the native #extend() method will keep your prototypes clean:
https://github.com/jashkenas/underscore/blob/master/underscore.js#L838

Related

jQuery Plugin structure: Accessing JavaScript class inside plugin definition?

I have a question regarding the structure of a jQuery plugin that I found.
For better understanding, here is a simplified example of the plugins structure:
// Regular constructor function
function MyPlugin() {
this.myValue = "My Value";
}
// Methods on the prototype
MyPlugin.prototype.showValue = function() {
alert($.myplug.getValue());
}
MyPlugin.prototype.getValue = function() {
return this.myValue;
}
// jQuery plugin
$.fn.myplug = function() {
// Why is is possible to access $.myplug here although it's not created yet?
return this.each(function() {
$(this).html($.myplug.getValue());
});
};
// Create new MyPlug instance
$.myplug = new MyPlugin();
// Calling the jQuery plugin on a DOM element
$('div').myplug();
For the most part, I get what is happening. The actual plugin logic seems to be written as a normal JavaScript "class".
This is followed by a jQuery plugin definition – I think, actually, some new method is added to jQuery's prototype. This is where things get tricky to me:
How is is possible to access the class instance inside the plugin, although the class is instantiated after the plugin definition? Is there a mechanism at work similar to variable hoisting?
In case you want to try something, here is a Fiddle of the example: http://jsfiddle.net/kq8ykkga/
$(this).html($.myplug.getValue()); isn't evaluated until you call $('selector').myplug(), executing the function body.

Extending Backbone functions while keeping base functionality

I'm attempting to add a bit of processing functionality to Backbone.View in the initialize function that I want to be carried over to all my Backbone Views. The problem is, I'm using Marionette so I can't do something like this:
var BaseView = Backbone.View.extend({})
because Marionette extends Backbone.View itself. Here's what I would like to do:
// Add processoring logic to an extended version of Backbone.
Backbone.View.extend({
initialize: function(options){
if(options.hasOwnProperty("vents") {
// process vents
}
// native code. Calling the library's actual original function to maintain original functionality.
Backbone.View.initialize(this, aurguments);
}
})
var CollectionView = new Marionette.CollectionView({
vents: {VentCallName: function(){}}
// When initialize is called, it'll see the vents and deal with them automatically.
});
I'm just not sure how to add the functionality to Backbone.View while maintaining whatever function logic is already in there.
EDIT
How do I actually get the initial extended functionality into Backbone.View.initialize without making a new extended instance and basing all my views off that? I can't get Marionette to use that extended view, so the extra processing has to go into Backbone.View's initialize function.
If I do this, it loops back on itself:
Backbone.View.prototype.initialize = function(){
console.log("moooo");
// custom logic then run Backbone.View.initialize native code.
Backbone.View.prototype.initialize.apply(this, arguments);
}
Backbone.View.prototype.initialize.apply(this, arguments);
Edit
Okay, well that's a slightly different question.
var oldInitialize = Backbone.View.prototype.initialize;
Backbone.View.prototype.initialize = function(){
console.log("moooo");
// custom logic then run Backbone.View.initialize native code.
oldInitialize.apply(this, arguments);
}

JavaScript init function and its use

I'm new to JavaScript and saw a coode where a init function is used while declaring the object..I tried searching for "JavaScript init functions" but it does not take me to any correct document. Also, it does not provide me the exact application of this function…
I have modelled a function on how it looks like
var1 = Class.extend({
init : function(){ alert ('Hi'}
}
Question:
How does init does called? Is it similar to the init(initialization) method in Object oriented concepts.
Can you please provide a example on how init function could be called?
init is a custom function name, it may be called by the framework or by the object constructor and usually keeps place of a post construction method. For instance I declare it for jQuery plugins, like this:
;(function($, window, document, undefined) {
// Create the defaults once
var pluginName = "Display", defaults = {
cols : 32,
rows : 16
};
// The actual plugin constructor
function Display(element, options) {
// Object variables
this.options = $.extend({}, defaults, options);
this.size = {};
// Post construct
this.init();
}
// methods of the Display
display.prototype = {
init : function() {
this.setSize(this.options.rows, this.options.cols);
},
setSize : function(rows, cols) {
// calculates size
}
};
// JQuery Plugin declaration
// ...
})(jQuery, window, document);
With this, a call (from the correct scope) to new Display() will call the init method.
Init in most framework is used to be called after the object initialization. It is called automaticaly so you just put in the code you want to execute after the object is initialized. It is similar to constructor however it is not the same. For an example in backbone which is cool javascript framework (you see this init functions only in frameworks it is not native javascript method)
Constructor runs before Backbone sets up the structure. initialize is called inside the structure's constructor function. So basically if you need to augment anything before Backbone sets up the structure, use constructor if you need to augment anything after Backbone sets up the structure use initialize.

jQuery plugin patterns: something more object-oriented?

I'm working on a jQuery plugin, following the pattern detailed in the Authoring guide. Basically:
(function($) {
// Private
var doSomething = function($element, settings) { ... }
var doSomethingElse = function($element, settings) { ... }
// Public
var methods = {
init: function(options) { ... },
show: function() { ... },
hide: function() { ... },
update: function(content) { ... }
};
$.fn.myPlugin = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || ! method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.myPlugin');
}
};
})(jQuery);
Here's my dislike: I have to pass the same "instance" variables to all of the private functions. I'm still working on becoming a JS pro — so pardon my incorrect term usage — but if I were doing this same thing in Ruby or PHP, I'd create a class with all of these public and private members and methods, and each instance of the class would correspond to an $element. Then I could do something like this (in JS):
var firstElement = new MyPlugin($element, settings);
firstElement.doSomething();
Rather than passing $element and settings to doSomething(), it already has access to those via this.$element and this.settings.
Get where I'm going with this? I'm looking for a more object-oriented approach, I guess. Now, I totally understand that JS doesn't have classes like Ruby or PHP. But between constructor functions, the module pattern, and regular object notation (like methods above), I'm not sure which is the best option for a jQuery plugin.
Can someone help point me in the right direction? Maybe some examples of existing jQuery plugins that do this well? Thanks!
The jQuery UI Widget Factory might be a good solution. It's useful for creating any kind of stateful jQuery plugins and can be used entirely separate from the rest of the jQuery UI suit.
Some useful links:
http://bililite.com/blog/understanding-jquery-ui-widgets-a-tutorial/
http://wiki.jqueryui.com/w/page/12138135/Widget-factory
http://ajpiano.com/widgetfactory/ (presentation)
If you want a more bare bone solution I'd go with either a regular Constructor + prototype setup to do things "properly" or use the Revealing Module Pattern to create a function that takes the element and any options as arguments and returns the public methods.
An example using the Revealing Module Pattern:
function myPlugin (element, options) {
var privateVar;
function privateFunc () {}
function publicMethod () {}
return {
publicMethodName: publicMethod
};
}
This pattern is a bit more tidy than a traditional prototypal set up, but does not take advantage of the prototype chain.
Edit: To clarify, when using any of these patterns you are supposed to create a new instance for each element/use.
It isn't necessarily a good idea to store any kind of stateful information in the plugin itself since it would be shared by all instances. One option is to store that data elsewhere, outside of the plugin.
The Plugins/Authoring page has a Data section which describes how to store information for use by your plugin on a per-element basis using the data() function.
Using data helps you keep track of variables and state across method
calls from your plugin. Namespacing your data into one object literal
makes it easy to access all of your plugin's properties from one
central location, as well as reducing the data namespace which allows
for easy removal if need be.
The example provided on the page uses the plugin pattern described in your post, but allows "instance" variables to be stored with the element they're associated with.
One key thing to remember when doing this is:
Always namespace your methods, events and data.
Edit:
It should be noted too, that in your example some of your functions expect $element as a parameter, but this isn't necessary since this will refer to the right thing when those functions are called through the plugin (because apply() is being called and setting the context to the correct this).

Customising a JQuery Element

Is it inadvisable to add methods to a JQuery element?
eg:
var b = $("#uniqueID");
b.someMethod = function(){};
Update
Just to clarify, I am working on a JS-driven app that is binding JSON data to local JS objects that encapsulate the business logic for manipulating the actual underlying DOM elements. The objects currently store a reference to their associated HTML element/s. I was thinking that I could, in effect, merge a specific instance of a jquery element with it's logic by taking that reference add adding the methods required.
Well, there's nothing inherently wrong with it. It is, however, pretty pointless. For example:
$('body').someMethod = function(){};
console.log($('body').someMethod); // undefined
You are attaching the new function only to that selection, not to all selections of that element.
What you should do instead is to add a new function to jQuery.fn, which is a shortcut for jQuery.prototype:
jQuery.fn.someMethod = function() {
if (this[0].nodeName == 'body') {
// do your function
}
return this; // preserve chaining
};
The problem is that your function would be quite transient. A further requery and it will be gone. You can extend the jQuery object itself by $.fn.someMethod = function() {} and this method will be available for all queries.
$.fn.someMethod = function() {}
var b = $("body");
b.someMethod();
Or you can create a jQuery plugin. You can define a plugin this way:
$.fn.someMethod = function(options) {
# ...
});
Call it using $('body').someMethod();

Categories

Resources