How to manually call Backbone.js view's method - javascript

I'm writing a browser extension for a site that uses Backbone.js. Its pertinent code looks like the following (names have been changed to protect the innocent):
var BigContainer = BigContainer || {};
(function($, exports) {
var Thing = Backbone.View.extend({
...
useful_func: function() {
// Does something I need to call
},
...
});
(function($, exports) {
BigContainer.BaseView = Backbone.View.extend({
...
render: function() {
this.local_thing = new Thing({
el: '.local_thing'
});
}
...
});
I am also inserting some code in a <script> block to listen for postMessage() calls I make from my extension's injected javascript file. I would like to be able to call useful_func from there, but can't figure out how, or if I'm even supposed to (and if not, then how I can arrive at the same result).
As an example, I've tried the following references, all of which show up as undefined:
BigContainer.BaseView.$local_thing
BigContainer.BaseView.local_thing
Thing
document.getElementsByClassName('local_thing')[0].useful_func
Importantly, since I'm writing an extension for a site I don't own, I can't modify the site's Backbone.js code to help myself out. I need to work with what's there.

With the line BigContainer.BaseView = Backbone.View.extend({, you are defining a new View type called BaseView, but it is only the definition. What you need is the actual instance of the view in your code. That would be somewhere where you do new BaseView (in this case, it's the following:)
// Where view is created
(function($, undefined) {
BigContainer.OtherThing = {
...
create: function(config, params) {
this.view = new BigContainer.BaseView(...);
}
...
})
With that found, you would do something like this:
// Your code, reach into that instance and its subview, and call 'usefulFunc'.
BigContainer.OtherThing.view.local_thing.useful_func();

Related

Loosely coupled JS modules - Backbone inheritance with random file load order?

Sorry for the horrible post title but it's hard to sum up.
I'm defining JS modules using the revealing module pattern in seperate files, wrapped in IFFEs, under the namespace "App". By checking for the existence of "App" in each file, they can load in any order (script tags are injected into the HTML through a build process - so probably are added in alphabetical order).
Some of the modules are purely Backbone views.
The following 2 files work fine, loaded in any order:
app.js:
App = window.App || {};
App.Main = (function(){
var init = function(){
var view = new App.BaseView();
}
return {
init: init
}
})();
base_view.js:
App = window.App || {};
App.BaseView = (function(){
var View = Backbone.View.extend({
initialize: function(){
console.log('base view init');
}
});
return View;
})();
The whole app is triggered on document ready by calling App.Main.init(). I know that all modules have loaded by then - in whatever order;
However, if I want another view to extend BaseView, I need to know that base_view.js has loaded previously. The following file will not work if it was loaded before base_view.js (even though it's checking for the existence of "App" and creating it if necessary, it relies on BaseView already being defined):
another_view.js:
App = window.App || {};
App.AnotherView = (function(){
var View = App.BaseView.extend({ //App.BaseView may not be defined!
initialize: function(){
console.log('base view init');
}
});
return View;
})();
Is there a pattern I can use to get around this?
I'm sure you're looking for a better answer than this but you could simply try wrapping it inside a sort of 'wait for it' interval loop?
App = window.App || {};
var interval = setInterval(function() {
// get elem
if (typeof App.BaseView == 'undefined') return;
clearInterval(interval);
// the rest of the code
}, 10);

JQuery Plugin Pattern - Code Organization for multiple scripts

I'm developing a client using JQuery based on lightweighted plugin pattern as listed here.
https://github.com/jquery-boilerplate/jquery-patterns/blob/master/patterns/jquery.basic.plugin-boilerplate.js
I've been working on one file, but it's getting bloated with over 1000 lines of code. So I've decided to split scripts, but I haven't been able to locate best practice for keeping multiple scripts with jQuery.
My main script is the following:
;(function($, window, document, undefined) {
function MainClass(){
this.other = new Otherclass(); // Otherclass is defined in separate script
}
MainClass.prototype = {
...
}
$.fn.mainclass = function(){
...
}
})(jQuery, window, document);
HTML is the following:
<html>
<head>
// JQuery included
<script type="text/javascript" src="mainclass.js></script>
<script>
$(function() {
$("body").mainclass();
});
</script>
</head>
</html>
Question: I need to define otherclass on the separate file. What is the best way to accomplish this? If Plugin Pattern wasn't meant to have multiple scripts, are there any other practice suitable for this?
Thank you.
The module pattern that you are using is a good first step in the right direction. The plugin pattern was really intended to encapsulate one specific functionality for a given set of elements and follows the open/closed principle pretty well, by design (open for extension). However, it isn't a good approach for multiple object interaction due to its primary behavior as an extension method of the jQuery object.
One thing that I was able to do to split my JavaScript out into pages/multiple files was to use a combination of Namespacing and Module Augmentation/Importing/Exporting.
The namespacing was great for importing and dereferencing other portions of the application and the module pattern helped with selection of exposure and exporting just the right amount of reusable members of an object. From there, I could dereference any object that was in the namespace, create new instances from that, and so forth:
//In some common site-wide file, declare a common namespace and known base objects within it:
var App = {
View: {},
Utilities: {}
};
// view.js
App.View = (function($, window, document, undefined) {
var localProp = "Hi, i'm a private property for App.View to access";
function doSomething(){
// a private method for use
}
return {
reuseableMethod: function() {
// exported for access through App.View.reusableMethod()
}
};
})(jQuery, window, window.document, undefined);
// another script, more specific, different file
// NOTE: the import and export of App.View and view
(function($, window, document, view) {
// consume your other objects after importing them
var me = Object.create(view);
me.reuseableMethod();
function localFunction() {
//do something private
}
})(jQuery, window, window.document, App.View);

understanding a modular javascript pattern

I'm trying to write 'better' javascript.
Below is one pattern I've found, and am trying to adopt. However, I'm slightly confused about its use.
Say, for example, I've got a page called "Jobs". Any JS functionality on that page would be encapsulated in something like:
window.jobs = (function(jobs, $, undefined){
return {
addNew: function(){
// job-adding code
}
}
})(window.jobs|| {}, jQuery);
$(function(){
$('.add_job').on('click', function(event){
event.preventDefault();
window.jobs.addNew();
});
});
As you can probably deduct, all I've done is replaced all the code that would have sat inside the anonymous event-handler function, with a call to a function in my global jobs object. I'm not sure why that's a good thing, other than it's reduced the possibility of variable collisions and made the whole thing a bit neater, but that's good enough for me.
The - probably fairly obvious - question is: all my event-binding init-type stuff is still sitting outside my shiny new jobs object: where should it be? Inside the jobs object? Inside the return object inside the jobs object? Inside an init() function?
I'm just trying to get a sense of a stable, basic framework for putting simple functionality in. I'm not building JS apps, I'd just like to write code that's a little more robust and maintainable than it is currently. Any and all suggestions are warmly welcomed :)
You can break down your application in whatever number of modules / objects you like too.
For instance, you can have another object / module which caches and defines all your DOM nodes and another one, which just handles any event. So for instance:
(function ( win, doc, $, undef ) {
win.myApp = win.myApp || { };
var eventHandler = {
onJobClick: function( event ) {
event.preventDefault();
myApp.addNew();
}
};
var nodes = (function() {
var rootNode = $( '.myRootNode' ),
addJob = rootNode.find( '.add_job' );
return {
rootNode: rootNode,
addJob: addJob
};
}());
$(function() {
myApp.nodes.addJob.on( 'click', myApp.handler.onJobClick );
});
myApp.nodes = nodes;
myApp.handler = eventHandler;
}( this, this.document, jQuery ));
It doesn't really matter how you create singletons in this (module) pattern, either as literal, constructor, Object.create() or whatnot. It needs to fit your requirements.
But you should try to create as many specific modules/objects as necesarry. Of course, if makes even more sense to separate those singletons / modules / objects into multiple javascript files and load them on demand and before you can say knife, you're in the world of modular programming patterns, dealing with requireJS and AMD or CommonJS modules.
Encapsulation-wise, you're fine: you could even just declare addNew in the jQuery closure and you'd still avoid the global scope. I think what you're getting at is more of implementing something close to an MVC architecture.
Something I like to do is create an object that you instantiate with a DOM element and that takes care of its own bindings/provides methods to access its controls etc.
Example:
// (pretend we're inside a closure already)
var myObj = function(args){
this.el = args.el; // just a selector, e.g. #myId
this.html = args.html;
this.bindings = args.bindings || {};
}
myObj.prototype.appendTo = function(elem){
elem.innerHTML += this.html;
this.bindControls();
};
myObj.prototype.remove = function(){
$(this.el).remove(); // using jQuery
};
myObj.prototype.bindControls = function(){
for(var i in this.bindings){ // event#selector : function
var boundFunc = function(e){ return this.bindings[i].call(this,e); };
$(this.el).on(i,boundFunc);
}
};
The way you are doing it right now is exactly how I do it also, I typically create the window objects inside the anonymous function itself and then declare inside that (in this case: jClass = window.jClass).
(function (jClass, $, undefined) {
/// <param name="$" type="jQuery" />
var VERSION = '1.31';
UPDATED_DATE = '7/20/2012';
// Private Namespace Variables
var _self = jClass; // internal self-reference
jClass = window.jClass; // (fix for intellisense)
$ = jQuery; // save rights to jQuery (also fixes vsdoc Intellisense)
// I init my namespace from inside itself
$(function () {
jClass.init('branchName');
});
jClass.init = function(branch) {
this._branch = branch;
this._globalFunctionality({ globalDatePicker: true });
this._jQueryValidateAdditions();
//put GLOBAL IMAGES to preload in the array
this._preloadImages( [''] );
this._log('*******************************************************');
this._log('jClass Loaded Successfully :: v' + VERSION + ' :: Last Updated: ' + UPDATED_DATE);
this._log('*******************************************************\n');
};
jClass._log = function() {
//NOTE: Global Log (cross browser Console.log - for Testing purposes)
//ENDNOTE
try { console.log.apply(console, arguments); }
catch (e) {
try { opera.postError.apply(opera, arguments); }
catch (e) { /* IE Currently shut OFF : alert(Array.prototype.join.call(arguments, ' '));*/ }
}
};
}(window.jClass= window.jClass|| {}, jQuery));
The reason I leave them completely anonymous like this, is that let's say in another file I want to add much more functionality to this jClass. I simply create another:
(function jClass, $, undefined) {
jClass.newFunction = function (params) {
// new stuff here
};
}(window.jClass = window.jClass || {}, jQuery))
As you can see I prefer the object.object notation, but you can use object literals object : object, it's up to you!
Either way by leaving all of this separate, and encapsulated without actual page logic makes it easier to have this within a globalJS file and every page on your site able to use it. Such as the example below.
jClass._log('log this text for me');
You don't want to intertwine model logic with your business logic, so your on the right path separating the two, and allowing for your global namespace/class/etc to be more flexible!
You can find here a comprehensive study on module pattern here: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html It covers all the aspects of block-scoped module approach. However in practice you gonna have quite a number files encapsulating you code, so the question is how to combine them property. AMD... multiple HTTP requests produced by every module loading will rather harm your page response time. So you can go with CommonJS compiled to a single JavaScript file suitable for in-browser use. Take a look how easy it is http://dsheiko.github.io/cjsc/

Why can't my jQuery.Widgets namespace be accessed?

I've been reading alot about the advantages of using the jQuery.Widget Factory for my plugins. One of the capabilities touted is how the jQuery.widget creates a namespeace for your widget. This is attractive, as I can maintain my current namespacing (naturally) within the jQuery context.
THE PROBLEM:
I keep getting "$(".myWidget").namespace.newWay is not a function" error.
For the following element...
<div class="myWidget"></div>
THIS EXAMPLES CODE WORKS:
While nice...this is NOT what I am trying to achieve...as I still want my namespace to be honored.
var workingVersion = {
_init: function () { /* Do Something*/ }
};
$.widget("ui.workingVersion", workingVersion);
$(document).ready(function () {
$('.myWidget').workingVersion();
});
HOWEVER, MY CODE FAILS:
var namespace = namespace || { };
;namespace.newWay = (function ($, window, document, undefined) {
return function (options) {
var self = this;
this._create = function () {
// Do something
},
this._init = function() {
// Do something
},
this.publicFunction = function () {
// Do something
};
};
})(jQuery, window, document);
$(document).ready(function () {
$.widget("ui.namespace.newWay", namespace.newWay); //<-- Namespace does get appended
$('.myWidget').namespace.newWay({ type: 'testing' }); //<-- But still fails here
});
MY QUESTION IS:
Why does it fail?
RELATED READING:
Understanding jQuery UI widgets: A tutorial
Tips for Developing jQuery UI 1.8 Widgets
This answer comes a bit late, maybe, but I was struggling with the same thing and had to do some reading.
$() in General
The $() instance is a no-namespace shortcut list to different functions spread out over different namespaces. You can add more functions to this shortcut list by writing:
$.fn.myFunction = function() {
...
};
Which then will be accessed by calling
$("...").myFunction();
If you add two functions by the same name the latter one will overwrite the first one.
Widgets
When you create a widget with a namespace it's created with it's namespace, as you would expect, but to $() it's added without it's namespace, as a simplified shortcut to your real widget-with-shortcut. This is done using $.widget.bridge(). You can therefore create your own namespaced link to $() by writing like this:
$.widget.bridge("namespace_myFunction", $.namespace.myFunction );
And then access your widget like this:
$("#myDiv").namespace_myFunction();
To use a widget directly with it's original namespace you can instead invoke it like this:
$.namespace.myWidget(
{
option1: "",
option2: ""
},
$("#div")
);
Hope this will clarify a little...

backbone.js Issue with module defining

I follow this pattern to organize my js application.
As that example says our application should has the single entry point. File application.js doing that work.
// Filename: application.js
var chat = {
// Create this closure to contain the cached modules
module: function() {
// Internal module cache.
var modules = {};
// Create a new module reference scaffold or load an
// existing module.
return function(name) {
// If this module has already been created, return it.
if (modules[name]) {
return modules[name];
}
// Create a module and save it under this name
return modules[name] = { Views: {} };
};
}()
};
// Using the jQuery ready event is excellent for ensuring all
// code has been downloaded and evaluated and is ready to be
// initialized. Treat this as your single entry point into the
// application.
jQuery(function($) {
$(document).ready(function(){
var foo = new Application.module('Chat').Collection();
});
});
// Filename: chat-module.js
(function(chat){
chat.Model = Backbone.Model.extend({ ... }),
chat.Collection = Backbone.Collection.extend({ ... }),
})(Application.module('Chat'));
It seems well but if try to define chat module for example and invoke it later I have the following error:
Uncaught TypeError: Property 'Collection' of object #<Object> is not a function
I think that error due jQuery ready invokes when chat-module.js not available yet.
How can I resolve that problem?
Your code creates an object and assigns it to the global variable chat, which has a module function as a property:
var chat = {
module: function...
};
...but then when you use it, you use Application.module rather than chat.module.
Application.module('Chat')
and
var foo = new Application.module('Chat').Collection();
It seems to me that your chat variable should be called Application.
Also note that you're using module in two different ways, both with new and without. Without would be the correct use based on your code. It will work both ways because module returns a function (which is an object), and so that will override the normal new behavior, but it means that using new serves no purpose and is misleading to someone reading the code.

Categories