backbone/requirejs view strange benavior - backbone.js

i m doing reverse engineering and comepletely cant get how my backbone/requirejs view script works. Because requirejs documentation says that names of modules must be the same, but here is the code which works with just "a,b,c,d" modules declaration. can somebody help what should i read to understand?
"use strict";
define([
"underscore",
"backbone",
"jquery",
"util/numeral",
"text!sa-utils/js/templates/KeyIndicatorResults.html",
"css!sa-utils/css/KeyIndicator.css"],
function(a,b,c,d,e,f){
var g = some code working
return g
})

Names of modules are what you see in the dependencies array as strings ([
"underscore", ...])
a,b,c,... here are just arguments names, it is JavaScript and RequireJS doesn't have anything to do with what the developer decided to name them. Here they are meaningless because you are likely looking at uglified code.

Related

AngularJS, RequireJS, JQuery loading in wrong order

I'm developing simple AngularJS (I'm quite new with Angular) application and I encountered problem that js are loading in wrong order. Below there are relevant (I hope) snippets of my app.
index.html
(...)
<script data-main="scripts/main.js" src="scripts/require.js"></script>
(...)
main.js
requirejs.config({
baseUrl: 'scripts',
paths: {
angular: '../../bower_components/angular/angular',
jquery: 'jquery',
domReady: 'domReady',
'jquery.scrollTo': '../../bower_components/jquery.scrollTo/jquery.scrollTo',
},
shim: {
jquery: {deps: ['domReady']},
'jquery.scrollTo': {deps: ['jquery']},
angular: {deps: ['jquery.scrollTo'], exports: 'angular'}
},
packages: []
});
requirejs(['angular', 'domReady', 'jquery', 'app', 'scripts', 'jquery.scrollTo'], function(angular, domReady) {
'use strict';
domReady(function() {
angular.bootstrap(document, ['myApp']);
});
});
app.js
define('app', ['angular', 'domReady', 'jquery', 'jquery.scrollTo'], function (angular) {
return angular.module('myApp', []);
});
scripts.js
require(['domReady', 'jquery', 'jquery.scrollTo'], function(domReady, $) {
domReady(function() {
console.log('scripts.run');
});
});
I assumed that loading order should be following:
main
domReady
jquery
jquery.scrollTo
angular
scripts
app
But in real loading order is following:
The most strange for me is why scripts.js is loaded before jquery.js and jquery.scrollTo.js if require statement define that it is dependent on domReady, jquery and jquery.scrollTo?
I suggest to remove jquery completely from your code (if its possible for you) and requirejs. AngularJS has great dependency injection module which you could use to support timing of loaded parts.
Also - you could try to inline ng-app attribute inside html code insted of invoking angular via boostrap call, than you won't need "domReady".
If you can, please tell something more about your app so we can give you better response on availible solutions.
deitch's statement regarding loading order is correct. RequireJS will guarantee that the order in which the factory functions of your modules (factory == the callback you give to define) are executed will respect the dependencies specified. As far as the order in which modules are fetched the only thing you can be sure is that a module will be fetched before its factory function is executed but RequireJS otherwise has the freedom to fetch modules in any order.
In the case you are showing us, note how the modules that are first fetched after main are those which do not have a shim configuration defined for them. Modules with a shim configuration require a bit more processing from RequireJS and thus follow a different code path.
While we're at it, a few bizarre things in your code:
A path configuration that just repeats the name of the module does nothing. For instance, jquery: 'jquery'. You could remove such path specifications.
You have require at the top level of scripts.js. You should have define there instead.
Your call to define in app.js specifies a module name (1st parameter to define). Leave the module name out.
You give a jQuery a shim configuration. jQuery calls define. Giving a shim to a module that calls define is likely to result in undefined behavior. Don't do this.

AngularJS loading modules

I'm having a really hard time trying to make modules working on an app I'm building.
This is the main file
main.js
'use strict';
angular.module('clientPortalPublic',[
'ngCookies',
'ngResource',
'ngAnimate',
'clientPortalPublic.components'
]);
angular.module('clientPortalPublic.components',[]);
And I have another file switch-login-effect.js
'use strict';
angular.module('clientPortalPublic.components').directive('switchLoginEffect',['$timeout', function($timeout){
//Content removed for clarification
}]);
The order that those files are being loaded is:
<script type="application/javascript" src="public/components/switch-login-effect.js"></script>
<script type="application/javascript" src="public/main.js"></script>
I know the switch-login-effect.js should be loaded later, since is requiring the main module, but it's being loaded dynamically and I don't control the order. BUT using manual bootstrapping shouldn't angular deal with it?
This is how I'm bootstrapping it
angular.element(document).ready(function() {
angular.bootstrap(document, ['clientPortalPublic']);
});
If I run the code above I get:
Error: [$injector:nomod] Module 'clientPortalPublic.components' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Thanks!
You are declaring a directive on a non-existant module when switch-login-effect.js loads first. It looks like you are trying to dynamically control what elements are included in the clientPortalPublic.components module simply by adding or removing scripts, but I don't think angular's dependencies are set up for that. A main reason to have those dependencies is to know exactly what you are getting.
The clientPortalPublic.components module should be defined in one script file if possible. If you have various components you can create different modules for each, but the definition of your application module should know what it is getting by the dependencies it requires. That would cause debugging headaches for one reason, "Why is my directive not working? I'm loading the components module..." (but you missed a script file you have no way to know that you need)
I really don't advise creating your app this way, but if you are dead-set you could catch the error and create the module at the start of each individual component file (and in your main.js in case you don't actually have any components but still want to require the module) so it doesn't matter which one is loaded first:
try {
angular.module('clientPortalPublic.components');
} catch (err) {
angular.module('clientPortalPublic.components',[]);
}
Or more simply just uses javascript to see if it's been executed:
var componentsModule = componentsModule ||
angular.module('clientPortalPublic.components',[]);
After reading some angular good practices and paying more attention to angular seed, I have it working.
THe thing is that they recommend to do the following when you have an structure similar to:
app/
app/components
app/components/component1
app/components/component2
app.js => angular.module('main',['main.components']);
app/components/components.js => angular.module('main.components',['main.components.component1', 'main.components.component2']);
app/components/component1.js => angular.module('main.components.component1',[]);
app/components/component2.js => angular.module('main.components.component2',[]);
Having that structure make sense and works perfectly.
:)

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.

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