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);
Related
I have a javascript file that declares the variable below:
var page = page || {};
The above file is included in another javascript file that wants to make use of page variable. I can see that variable in intellisense when trying to type it.
But at runtime, I am getting error that :
page is not defined.
I am posting more elaborate code:
First file is page.js that has just one line
var page = page || {};
Second file uses the above variable:
/// <reference path="page.js" />
page.current = function () {
};
There is final third file:
/// <reference path="../pagescripts/page-current.js" />
define(function () {
var Agencies = function (app, datacontext, logger, config, router) {
var myPage = page.current;
//The above line throws error saying page is not defined.
});
};
This pattern is commonly used when using the same namespace object across multiple files. By putting
var page = page || {};
at the top of each file that touches that namespace, you're guaranteed that page will point to the same object, and you can load them in any order, if your code permits.
// page1.js
var page = page || {};
page.doSomething = function() {};
// page2.js
var page = page || {}
page.doSomethingElse = function() {};
// page3.js
var page = page || {};
page.doThirdThing = function() {};
Make sure you load the javascript file that defines the variable before the file/script tag that uses it.
If you can not change the order of script file load for some reason, then you may use dom onready function to access this variable. As a rule of thumb, you should delay execution of your logic till dom is ready. e.g. in jQuery you can use
$(document).ready(function() {
// application init logic
// or start execution of functions
if(page && page.whatever) {
page.whatever();
}
})
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();
Oh hi,
I saw some interesting posts about this subject but I think it's a really personal question that needs a customized answer. So I'm asking you what is the best way to organize my code for a Javascript plugin that need to be the more unobstructiv posible.
So my code looks like that :
var myApp = (function(){
//here are my global methods or variables
var self = this;
return {
method1:function(){}
method2:function(){}
method3:function(){}
}
})() || (myApp = {})
myApp.method1();
I execute the method1 that calls or use the entire code of my app.
I think i could add and onload event with addEventListener method to execute this method1, and i guess my code could have a better organisation.
I want to precise that my plugin is a bit small, like 200 lanes of javascript code, and it must be in Vanilla js. It's used on a single page in a website, no need to do a prototype class called with "new", in my opinion.
It really depends on your project and what you're trying to obtain.
There are several patterns that help you organize and maintain your code better.
I for one use a combination of patterns that I've made myself comfortable with among the years.
Here's my boilerplate for a module of my application :
;(function(global, udnefined){
var app = global.app || {},
moduleName = 'util',
module = app[moduleName] || {};
// "private" vars
var version = "1.2";
// fake "private" members (the udnerscore naming convention)
module._bindEventHandlers = function(){
// code here
// for chainability purposes
return this;
}
// "public" method
module.someMethod = function(){
// for chainability purposes
return this;
}
// "public" method
module.someOtherMethod = function(){
// for chainability purposes
return this;
}
// the init method
module.init = function(){
this
._bindEventHandlers()
.someMethod();
}
app[moduleName] = module;
global.app = app;
})(this);
And then, in your app (in the app initialization or whenever you actually need the module) you can simply call :
app.util.init();
app.util.someOtherMethod();
The provided module is highly reusable for creating new modules, because most modules should have an initialization logic (the init method), most of them would listen to some events (be it dom or custom events) - the _bindEventHandlers method - and it doesn't pollute the global namespace with variables (it just adds an object to the main app).
i use somthing the lines of this. all depenting on what i need to get done
(function(app, undefined){
var module = app.module = (function(){
var privatestuff
return {}
}())
var singelton = app.singleton = (function(){
var Module = function(){}
module.prototype.method1 = function(){}
return new Module()
}())
var ModulePrototype = app.ModulePrototype = function(){
var Module = function(){}
module.prototype.method1 = function(){}
return Module
}
}(myApp = window.myApp ||{}))
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/
I'm using the javascript module pattern, and have this so far:
var APP;
if(APP == undefined) {
APP = {};
}
APP = (function() {
var userId = -1;
var privateVar = '';
var _init = function($userId) {
userId = $userId;
};
var _publicMethod = function($id){
privateVar = id;
};
return {
init = function($userId) {
_init($userId);
},
publicMethod = function($id) {
_publicMethod($id);
}
};
})();
I then have a common utils module:
APP.utils = (function(){
})();
And then per page I am planning on having a module, so I don't wireup events (button clicks etc) for no reason on pages where these DOM elements don't event exist:
APP.homePage = (function(){
return {
};
})();
So each module will have a init() method that I will call on the page to run things that have to be run (e.g. wiring up events, setting variables like say userId etc):
$(document).ready(function() {
APP.init(<%= user.id %>);
APP.homePage.init('abc');
});
So now if the files get too big, I can break them out into separate files also.
What if one module needs to call another, I guess the only way for this to work is to do this via the public api right?
e.g. what if homePage needs userId, should I pass that in the homePage#init method?
How is my coding style, any obvious style that is not considered best practise?
Any comments on this approach? Is it good in general?
What if one module needs to call another, I guess the only way for this to work is to do this via the public api right?
Yes
e.g. what if homePage needs userId, should I pass that in the homePage#init method?
No. I'd not repeat the userId code in all modules, but offer a public getter for it in the default module.
Any comments on coding
This code
var APP;
if(APP == undefined) {
APP = {};
}
APP = ...
is quite useless. You don't need to check for object existance here, because you overwrite it anyway. That also means that this code must be the first to execute. If you want to make the modules independent from load order, you'd need to use something like
var APP = (function(a) {
var private_vars; // ...
a.init = ...
a.publicMethod = ... // add them to the object instead of creating new one
a.getPrivate = function() {
return private_vars;
};
return a;
})(APP || {}); // create one iff not already existing
// other file:
var APP = APP || {};
APP.utils = ... // add object to namespace
The code
var _publicMethod = function($id){
privateVar = id;
};
looks a bit odd. First, the underscore usually denotes a semiprivate (public-but-not-to-be-used) attribute of objects and should not be used for variable names. That's not the case in here as the function will be exposed as the "publicmethod" property of APP. Use the underscore there if you want it. Second, there is no need to use a function expression here. The code is in the module's local scope, and using a function declaration both makes it available everywhere in that scope and allows naming the function. You should use
function publicMethod($id) {
privateVar = id;
}
a.publicMethod = publicMethod;
The module pattern is, in my opinion, a really nice way to organize your code. To answer your questions:
1) Yes, your modules can only access methods and properties of other modules which have been exposed in the object they return.
2) I think your coding style looks pretty good. I'd make these changes:
APP = (function() {
var _userId = -1;
var _privateVar = '';
var init = function($userId) {
_userId = $userId;
};
var publicMethod = function($id){
_privateVar = id;
};
return {
init : init,
publicMethod : _publicMethod
};
})();
First, underscores are generally meant to denote "private" properties or methods. Secondly, you can do away with the extra functions in the object being returned and just point straight to the methods or properties you care about. This is generally referred to as the "Revealing Module Pattern", because even the public methods aren't defined within the returned object - they're simply referenced.
3) This approach is definitely a nice way to encapsulate code. You get the benefit of private and privileged methods, and you generally end up with a nicer API because you're only exposing things that need to be public.
Well done.