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).
Related
ngMock does some magic to automatically include itself if you include angular-mocks.js in your index.html.
What's the simplest way to force angular to load a module in test mode simply by including a file and not having to edit any module dependencies.
The only way to load a module is by calling angular.module(...). ngMocks loads "itself" by calling:
angular.module('ngMock', ['ng']).provider(...).config(...);
You don't need to declare a module as a dependency to load it. You can just include angular.module('<moduleName>', [<moduleDependencies>...]); in its script.
If you mean "how is ngMock automagically added to the dependency list of any module loaded using window.module or angular.mock.module, it is because ngMocks creates a custom injector, such that it takes the list of dependencies and prepends 'ngMock':
window.inject = angular.mock.inject = function() {
...
return isSpecRunning() ? workFn() : workFn;
...
function workFn() {
var modules = currentSpec.$modules || [];
modules.unshift('ngMock'); // <-- this line does the trick
modules.unshift('ng');
...
You could create your own function that prepends your module in the list of dependencies before instantiating, but I hardly believe this will help in testing. On the contrary, it will be one more source of errors (and will result in possibly "hiding" dependency errors).
I would like to have few global variables that are UI related (i.e. open menu state). I decided to put these in $rootScope so they're always accessible.
This is the code I've written:
(function (angular) {
angular
.module("App", [])
.run(["$rootScope", function ($rootScope) {
angular.extend($rootScope, {
ui: {
menu: false,
...
}
});
}]);
})(angular);
I've deliberately used angular.extend, to make sure that consecutive manipulations to the same object are retained. And I think it's also more clean and safe than adding several properties to any object one by one.
Problem
Upper code doesn't do anything though. When I run my application and check root scope by calling:
$("body").scope().$root.ui
I get undefined until some property within ui gets manipulated by ng-click directives on my application. Only then my ui gets a reference... But it's still not the one I've defined in the run() function but rather angular generated object property that ng-click directive generated as per expression.
What am I doing wrong?
Resolved - module got overwritten
Ia managed to resolve it myself. Code contained in the upper question isn't sufficient to show the actual problem in my application. The problem was the way I was loading module requirements and file ordering.
I'm loading files in this order:
app.js
routing.js
service.something.js
...
filter.something.js
...
So I thought to add module requirements to my app module in subsequent files (make ti actually modularized). This would make it simple to either include or exclude particular files without any runtime errors. It would also allow loading additional files dynamically as application runs.
The problem with my code was that I've overridden my original module in subsequent files. When I added all module requirements into app.js everything everything started working.
Possible workaround
I can see that I'm not the only person that would like this kind of functionality. Lasy module requirements loading is possible as per this Google groups' post.
What it does is it creates a new injector function
instanceInjector.loadNewModules = function (mods) {
forEach(loadModules(mods), function(fn) { instanceInjector.invoke(fn || noop); });
};
that can later be used by individual modules to add themselves as requirement to the main application module by doing this:
$injector.loadNewModules(["Module1", "Module2", ...]);
Although it would be much better (my opinion) if there was an additional function on Module type called requires() so one could do this instead:
angular.module("MainModule").requires(["AdditionalModule", "OtherModule", ...]);
I think that would make it more concise and easy to use and understand.
I need to write a custom module for AngularJS, but I can't find any good documentation on the subject. How do I write a custom module for AngularJS that I can share with others?
In these situations were you think that the docs can't help you any more, a very good way to learn is to look at other already-build modules and see how others did it, how they designed the architecture and how they integrated them in their app.
After looking at what others did, you should have at least a starting point.
For example, take a look at any angular ui module and you will see many custom modules.
Some define just a single directive, while others define more stuff.
Like #nXqd said, the basic way to create a module is:
// 1. define the module and the other module dependencies (if any)
angular.module('myModuleName', ['dependency1', 'dependency2'])
// 2. set a constant
.constant('MODULE_VERSION', '0.0.3')
// 3. maybe set some defaults
.value('defaults', {
foo: 'bar'
})
// 4. define a module component
.factory('factoryName', function() {/* stuff here */})
// 5. define another module component
.directive('directiveName', function() {/* stuff here */})
;// and so on
After defining your module, it's very easy to add components to it (without having to store your module in a variable) :
// add a new component to your module
angular.module('myModuleName').controller('controllerName', function() {
/* more stuff here */
});
And the integration part is fairly simple: just add it as a dependency on your app module (here's how angular ui does it).
angular.module('myApp', ['myModuleName']);
If you want to look for a good example, you should look into the current module written in angularJS. Learn to read their source code. Btw this is a structure that I use to write modules in angularJS:
var firstModule = angular.module('firstModule', [])
firstModule.directive();
firstModule.controller();
// in your app.js, include the module
This is the basic one.
var newMod = angular.module('newMod', []);
newMod.controller('newCon', ['$scope', function ($scope) {
alert("I am in newCon");
$scope.gr = "Hello";
}]);
Here newMod is a module which has no dependencies [] and has a controller which has an alert telling you are in the controller and a variable with value hello.
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.
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.