backbone with requirejs : View and subviews and r.js - backbone.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.

Related

How to create a JS file with a variable name in AngularJS?

How can I include a JavaScript file in my Angular project but assign a name to all of its functions? I just included Underscore.Script and Lodash for the first time and noticed they both have actual names ("_" and "s")..
_.mixin(s.exports());
I've watched a few courses on JavaScript and Angular but cannot find anything that actually explains this or how to accomplish it.
In Javascript, the simplest way is when writing your library define all of your functions as properties of an object in the global scope.
var myLibrary = {};
myLibrary.myFunction = function(){
/* Your function code */
};
Then after including your file, you can access your functions like so:
myLibrary.myFunction();
A better way might be to wrap your library in a self executing function, which will help you avoid unintentionally adding properties to the global scope (a good practice)
(function(root){
var myLibrary = {};
myLibrary.myFunction = function(){
/* Your function code */
};
root.myLibrary = myLibrary;
}(window));
Please note that passing window to the self-executing function will work in the browser, but not in a different context (like nodejs).
If you want to create something specifically for Angular, I would suggest looking into angular services which is how you can create libraries that work with the Angular dependency-injection system.
in angular we have controllers, directives, services, factories and providers.
Lets take an example of Factory - "Customer" having function to get and set details.
app.module.js
angular.module("myapp", []);
Customer.js
angular.module("myapp").factory("Customer", function(){
function Customer(name, email){
this.name = name;
this.email = email;
}
Customer.prototype.getName = function(){
return this.name;
};
Customer.prototype.getEmail = function(){
return this.email;
};
Customer.prototype.setName = function(name){
this.name = name;
};
Customer.prototype.setEmail = function(email){
this.email = email;
};
});
CustomerController.js
angular.module("myapp").controller("CustomerController", ['Customer',
function(Customer){
var custObj = new Customer();
custObj.setName("Test");
custObj.setEmail("test#gmail.com");
console.log("Name: " + custObj.getName() + " Email: " + custObj.getEmail());
}
]);
Here app.module.js -- Angular App main module is initialised.
Customer.js is a JS and you can use this file and its functions by giving it a name "Customer" in CustomerController.js file.
Other answers tell you to make your own scripts modular. This is good, but it doesn't solve the problem of disambiguating Underscore and LoDash. So here's how to do that:
I would first recommend that you look into modular systems like RequireJS. Libraries like LoDash and Underscore are built to recognize and integrate with AMD style architectures, allowing them to coexist (however, these two libraries are redundant. LoDash is supposed to be a drop-in replacement for Underscore. But I digress.
If you do not use a module system (not to be confused with angular's module), you'll have to do the shim work yourself. It isn't hard, by any means, but it's a bit manual. Scripts specified in your HTML are executed in-order (caveat: there are asynchronous loaders out there, but they make your problem easier to solve, not harder).
So, for your particular problem, you can do this:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.8.0/lodash.js"></script>
<script>
var mylodash = _;
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
<script>
var myunderscore = _;
</script>
You will thereafter have access to both (feel free to name or group them however you'd like). Both of these libraries do a good job of not polluting the global namespace (which is attached to window in a browser). But if your library exposes lots of different methods, you'll need to cobble them all together yourself.
Simple? Sure, but in the long run, learn to use something like CommonJS or RequireJS. They not only solve this particular problem, but they also provide so many other benefits -- you'll be glad you did.

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

How do I use namespaces in Backbone with RequireJs

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.

Resources