How do I use namespaces in Backbone with RequireJs - backbone.js

I am unsure how I use namespaces in an modularized (RequireJs) Backbone environment.
I have thought a bit how it could look like but am totally unsure if this is the right way.
app.js (getting executed by main.js)
define('App', ['underscore', 'backbone', 'Router'], function( _, Backbone, Router){
function initialize(){
var app = {}; // app is the global namespace variable, every module exists in app
app.router = new Router(); // router gets registered
Backbone.history.start();
}
return { initialize: initialize }
});
messages.js
define('MessageModel', ['underscore', 'backbone', 'App'], function(_, Backbone, App){
App.Message.Model; // registering the Message namespace with the Model class
App.Message.Model = Backbone.Model.extend({
// the backbone stuff
});
return App;
});
Is this the right approach or am I fully on the wrong way (if yes please correct me!)

Have a look at the TODO Backbone + requireJs example:
https://github.com/addyosmani/todomvc

Found an real example app using namespaces like mentioned in the start post: https://github.com/nrabinowitz/gapvis
Just have to test it the next days

I'm new to backbone, but just read a snippet from the requirejs docs.
A module is different from a traditional script file in that it defines a well-scoped object that avoids polluting the global namespace. It can explicitly list its dependencies and get a handle on those dependencies without needing to refer to global objects, but instead receive the dependencies as arguments to the function that defines the module. Modules in RequireJS are an extension of the Module Pattern, with the benefit of not needing globals to refer to other modules.
To me, this sounds as if when using requirejs, you can forget all about namespaces, as requirejs takes care of it. You would just have access it differently. When you want to access it from another module, you'd put a path to the file in your array of dependencies, and and feed a respective variable to the following function.
define(["folder/a-script", "folder/another-script"], function(AScript, AnotherScript) {
// In here the scripts are loaded and can be used, but are called by
// their relative name in the anonymous function.
}
);
Anyway, perhaps in some cases there is still a need to namespace something, but I think in general, it's worth reading the docs to see if you need to.

Related

Why requireJs wouldn't load defined dependency modules?

I am having problem while using Require.js to load dependencies for my module. Basically I have following module in which I define extension of Backbone Model.
define(["models/services/ProjectServices"],
function (ProjectServices) {
var SomeModel = Backbone.Model.extend({
sample: function () {
var servicesFromDependency = ProjectServices; //undefined
var projectServices = window.require.s.contexts._.defined["models/services/ProjectServices"]; //defined and Ok
}
});
return SomeModel;
}
);
In this module I want to use already defined ProjectServices module. In order to do that I add it as a dependency. The thing is that within defined sample function ProjectServices is showing as undefined. But if I look directly into require defined modules it is showing there correctly and I can use it (although I do not want as I don't like to hack it this way). To add more context, I am also using this ProjectServices dependency on other module and there it is loaded properly through define function.
Any suggestions on why module would not be loaded?
Try this inside a module:
var ProjectServices = require('models/services/ProjectServices');
I think in many situations, there is no need for window global assignment and I try to avoid while using requirjs.
The only thing I can come up with is a possible circular reference, meaning that two modules require each other (which should not be the case).
As you say that the require works well in other modules, it should not be due to a missing return statement in the required module, or a wrong path. (You might check this anyway).

How to load backbone-deep-model with RequireJS?

While backbone-deep-model has AMD support for use with RequireJS, it depends on an underscore mixin in an external file called underscore.mixin.deepExtend.js that is not AMD compatible.
Looking at this question: How to mixin Underscore plugins in RequireJS?, it seems that I can manually mixin deepExtend into Underscore within the shim init setting in RequireJS.
...
shim: {
...
'deep-model': {
deps: 'underscore',
init: function() {
_.mixin(/* hash of deepExtend functions */);
return _;
}
}
}
...
However, I am stuck at what to do at this point since underscore.mixin.deepExtend does not return a hash of functions that _.mixin() requires.
Is there a way to load backbone-deep-model with RequireJS without modifying source code?
This may not be the answer you're looking for, but one option that I'd personally advise is to just leave Underscore (and any mix-ins, and probably also Backbone and jQuery) out of Require entirely. The main advantage of this approach (beyond making your problem go away as a side effect) is that you don't have start every require module by importing the same library (or libraries if you do the same with Backbone/jQuery).
True, this slightly "pollutes" the global space, but in my opinion having an _ (or $ or Backbone) variable in the global namespace won't hurt anything. It will however solve your problem, avoid the need for a shim at all, and save you a lot of importing. And of course you can (and should) still use Require for your own code, as keeping your variables from "polluting" the global namespace will save you future headaches.
Just a thought.
You can shim backbone as a dependency:
shim: {
// this is an example, I don't know what are the actual dependencies are
'deep-model': ['backbone', 'underscore']
}
and them when you add it as a dependency it will operate on backbone:
define(['backbone', 'deep-model'], function(Backbone) {
// backbone now has deepModel in it
});

Dealing with require.js

I guess I do not completely understand the way require.js works. Here is a a simple module I've created:
requirejs.config({
paths: {
'underscore' : 'libs/underscore-min',
'backbone' : 'libs/backbone-min'
}
});
define([
"underscore",
"backbone"
], function(_, Backbone) {
console.log(_);
console.log(Backbone);
var MyCollection = Backbone.Collection.extend({
initialize: function() {
this.on("all", function(event) {
console.log(event);
});
}
});
return MyCollection;
});
I load it from my html:
<script data-main="js/mycollection.js" src="js/libs/require.min.js"></script>
The problem is it works intermittently. Sometimes Backbone object is there in the function when I need it, sometimes it doesn't (and gives me http://requirejs.org/docs/errors.html#notloaded error). If I just hit reload in the browser, I'd get 50/50 change of it working.
I must be missing something really basic here, the reported error doesn't make any sense to me, I thought the whole idea of the require.js mechanism is that my function will be called only when all the dependencies are loaded.
Since Underscore and Backbone haven't been defined as AMD modules, require.js does not know that Underscore is a dependency of Backbone. So I guess what happens in 50% of your cases is that Underscore isn't loaded when Backbone tries to use it.
You can use the require.js shim config http://requirejs.org/docs/api.html#config-shim to tell require.js about the dependency structure.
My guess is that you're not using an AMD version of underscore and Backbone. If that's the case and the two packages aren't wrapped as AMD modules - then the define function which is meant for modules won't work like it should.
For non-module js scripts, the more appropriate form would be to use the require() function.
OR - you can find the AMD version of underscore and Backbone here. AMD support was taken out of Underscore and Backbone at some point.
AMD Underscore
AMD Backbone

backbone with requirejs : View and subviews and r.js

I have a view that requires requires Backbone, Undescore, jquery etc.
example
define(['jquery','undescore','backbone','subviewA', 'subviewB'], function($,_,Backbone, SubviewA, SubviewB){
var View = Backbone.View.extend({
//other methods here
render : function() {
this.subviewA = new SubviewA();
this.subviewA.render();
this.subviewB = new SubviewB();
this.subviewB.render();
return this;
}
});
});
subview example
define(['jquery','undescore','backbone','text!templates/subviewA'], function($,_,Backbone, template){
var SubviewA = Backbone.View.extend({
//other methods here
render : function() {
this.$el.html(template);
return this;
}
});
});
My question is if I need to include jquery, undescore and backbone in the subviews too ir I can omit them?
EDIT
I am asking cause in r.js I need every time to tell it to not to biuld those dependencies inside each module.
Theoretically, if you don't use the $ or _ symbols in your views, you don't need to list jquery and underscore as direct dependencies of your module (whether it is a view or a subview doesn't change that).
You do need to include backbone though, since you reference it directly with : Backbone.View. If you want to be absolutely sure that the Backbone symbol is defined you should declare it as a dependency.
Some libs register themselves both as AMD modules and as global variables (typically jquery does that). Backbone doesn't support AMD directly and registers itself at the global level regardless of how it is used. In theory you could not declare it as a dependency, but then you have the risk that require will try and load the script before backbone is loaded in which case the Backbone symbol will not be defined.
It doesn't matter much if you redondantly declare the dependencies except for the additional caracters, thus the additional script size.
You can omit any requirements which aren't used.
In your examples (ignoring omitted code!), you can remove jquery and undescore (sic) but not backbone (since you use it via Backbone.View.extend).
Obviously you need to keep your requirement names and variables in sync.

Best way to store backbone views

I've built my first backbone app and really enjoying the structure that backbone provides. However I have found myself with some minor annoyances which I am sure others have found solutions for.
So currently I have created a file structure like
models
index.js
user.js
views
index.js
user.js
So in my 'index.js' in the views folder I currently have all of the views, so lets say I have
headerView
footerView
buttonView
etc etc
So I currently have multiple 'views' inside one generic 'view js file' related to one page app. Problem is its not intuitive to find a particular view, I open a editor and find the correct view.
In other MVC, I would store each view in its own unique file, and use them as appropriate - do other users do the same here? I guess my concern is having multiple separate js files? I use the minify project to minify the js anyway, so could create a group, but wondering what others have done?
I would suggest that you take a look at require.js. Here is a tutorial that should get you started.
The core idea is sth. like the following.
each Model, View, Collection, Router, whatever resides in its own file and is called a module
at the top of each module you define its dependencies, meaning which other modules need to be loaded for your new module to work
require.js loads your dependencies and guarantees access via your self defined variables
Definiton (e.g childView.js)
define([
'jQuery',
'Underscore',
'Backbone'
], function($, _, Backbone){
return Backbone.View.extend({
//your usual view methods and properties
});
});
Reuse (e.g parentView.js)
define([
'jQuery',
'Underscore',
'Backbone',
'pathToChildView/childView.js'
], function($, _, Backbone, ChildView){
return Backbone.View.extend({
// your usual view methods and properties
// + access to your ChildView Modul
});
});
If you have trouble with the module loading syntax the sugared variant might be your friend.
It pays to separate each object into a view/template pair in hierarchical folders for better navigation. You then simply construct the child object in the view and pass the el element. This way you can reuse each object throughout the project as needed.

Resources