As suggested I wrap all my services into a module, So, I created files to organize them:
myServicesModule.js
var myServices = angular.module('myServices', []);
serviceA.js
myServices.service('serviceA', function(){...});
and serviceB.js
myServices.service('serviceB', function(){...});
etc etc.
As a good practice, we should try to avoid global variables, so is there any way to avoid declaring a global var myServices by something I guess module resolving by name? I understand by putting all services into a single file could solve this issue, but I don't want to create a huge file.
Second parameter of module function (dependencies array) is optional :
If you set the second parameter, it will create the module (and override any existing module with the same name) :
// Create the module
angular.module('foo', []).controller('FooCtrl', function($scope) {
// ...
});
If you do not set the second parameter, it will retrieve the module by its name and fail if module does not exist :
// Retrieve module by its name and fail if module does not exist.
angular.module('foo').controller('FooCtrl', function($scope) {
// ...
});
The angular.module is a global place for creating, registering and
retrieving Angular modules. All modules (angular core or 3rd party)
that should be available to an application must be registered using
this mechanism.
When passed two or more arguments, a new module is created. If passed
only one argument, an existing module (the name passed as the first
argument to module) is retrieved.
So this will work:
angular.module('myServices', []);
angular.module('myServices').service('serviceA', function(){...});
angular.module('myServices').service('serviceB', function(){...});
You don't need create variable for your service. It's possible tot do it that way`(in different files):
For example, file1.js:
angular.module('myServices', []);
file2.js
angular.module('myServices').service('serviceA', function(){...});
Related
I need to use this NoSleep.js inside my AngularJs controller. I installed NoSleep using bower but I need to inject it to my angularjs controller, but I have no idea on how do it, NoSleep isn't an angular service and I need to use this declaration var noSleep = new NoSleep(); in order to use it.
I'm using babel, webpack, gulp, karma
Any advise?
Typically when using non-angularjs libraries in an Angularjs application they are wrapped in a module. Then you inject the module into your app and then inject the service/factory you've wrapped with this into your controllers as needed, so you'd create a module that looks something like this:
(() => {
"use strict"
angular.module('nosleep.module', []).factory('nosleep', ['', function () {
return new NoSleep()
}])
})()
Then you'd inject the module into your main application module with something like:
angular.module('myApp', '[nosleep-module')
Then in your controllers that require access to nosleep you'd inject nosleep.
class myController {
constructor(nosleep) {
this.nosleep = nosleep
}
}
Then from within your control your can address it with this.nosleep.
It looks like NoSleep just declares a function in the global scope, so you could do something like this:
NoSleepService.js
(function () {
// place noSleep minified code here
angular.module('myApp').service('noSleep', NoSleep);
})()
That will create a NoSleep object within the enclosing function so that it doesn't pollute the global scope and register a new instance of it to your angular app.
If you have any JS lib and it's not an Angularjs lib, just add it using script tag in the html file and call it like you used to before they create AngularJs.
Have you tried it ?
Or go to the other way and wrap the lib with AgnularJs service (write an AngularJs service and call the lib method inside it), then inject this new service anywhere you want.
Update:
What #Mike Feltman and #richbai90 said in their answers was good and maybe enough for you, but I think it's better to build your service and call a methods you created, but inside these method use what ever library you want (it'll be like using interfaces in C#):
(function() {
'use strict';
angular.module('nosleep.module', []).service('nosleep', ['', nosleepFunc]);
function nosleepFunc() {
var nosleepObj = new NoSleep();
var service = {
method1: method1,
method2: method2
//... etc
};
function method1() {
return nosleepObj.method1();
}
// ..... other methods
return service;
}
})();
This way if you wanted to change nosleep lib to another one, and that new one lib has another method names, you need only to change in your service code.
The following code is working fine before minifiaction. Essentially, editableOptions is an angular value provided by the angular-xeditable library.
angular.module('common').run(function(editableOptions) {
editableOptions.theme = 'bs3';
}
)
However, when I minify, I get an injection error. I believe this is because editableOptions is getting minfied. How can I reference it differently so that this does not occur? Is there some way of referencing it starting with angular.module('xeditable') ?
Use the minification-safe method of defining injected objects:
angular.module('common').run(
['editableOptions',
function(editableOptions) {
editableOptions.theme = 'bs3';
}
]);
Angular team have a solution to this problem mentioned in one of their tutorials:
https://docs.angularjs.org/tutorial/step_05
A Note on Minification
Since Angular infers the controller's dependencies from the names of arguments to the controller's constructor function, if you were to minify the JavaScript code for PhoneListCtrl controller, all of its function arguments would be minified as well, and the dependency injector would not be able to identify services correctly.
We can overcome this problem by annotating the function with the names of the dependencies, provided as strings, which will not get minified.
This is another style to avoid minification and uglification problems:
function runModule(editableOptions) {
editableOptions.theme = 'bs3';
}
runModule.$inject = ['editableOptions'];
angular.module('common').run(runModule);
Todd Motto Angular Style
Guide
This aids with readability and reduces the volume of code "wrapped"
inside the Angular framework
I want to inject my sub module to main app, but I have injection error
(Error: [ng:areq] http://errors.angularjs.org/1.3.5/ng/areq?p0=SelectionCtrl&p1=not%20aNaNunction%2C%20got%20undefined
it's my main app
and it's my sub module
How can I fix that? Thanks!
You are messing up with module declaration. You declared angular.module('app.newProject') two times.
While creating it first time you registered SelectionCtrl. After that you created another module with same name angular.module('app.newProject,[]') with dependancy and registered TabController1 controller. When you created second module it overrides first one & now it has only TabController1 thats why angular is throwing error SelectionCtrl is required.
There are several appraoches resolve this approach.
Approach 1
Create a module and store it in some variable and use it whenever you want.
var controllerApp = angular.module('app.newProject', [])
.controller('SelectionCtrl',function(){
//code here
});
controllerApp.controller('TabController1',function(){
//your code here
});
Approach 2
Create a module, and whenever you want to use it, use it without dependency.
angular.module('app.newProject', [])
.controller('SelectionCtrl',function(){
//code here
});
angular.module('app.newProject').controller('TabController1',function(){
//your code here
});
Approach 3 (I wouldn't prefer this approach)
Create a module and append you components in linear manners.
angular.module('app.newProject', [])
.controller('SelectionCtrl',function(){
//code here
})
.controller('TabController1',function(){
//your code here
});
I would prefer you to go for Approach 2 which will provide you to bind components any by referring a module.
I'm trying to add Jasmine tests to my Marionette application by creating a specific context for each test containing a map that substitutes all dependencies with mocks except for the module being tested (as described here: http://bocoup.com/weblog/effective-unit-testing-with-amd/).
mockRequire = requirejs.config({
map: {
'*': {
'dep1': '../mocks/dep1'
}
}
});
mockRequire(['appTest'], function(){...})
However since my module appTest has a nested call to require the context is lost:
//appTest.js
define([],
function () {
...
require(['dep1'], function (dep1) {
//Here is not the mocked dep1 but the real one.
})
}
);
So the question is how I can tell requirejs to use the same context for all child calls to require/define or if there are any other ways to solve this.
Change your module definition so that it requires require:
define(['require'], function (require) {
Without it, you use the global require. With it, you use a require that has the proper context. From the documentation:
Note that "require" is specified as a dependency for the module. This allows the require() function that is passed to the function callback to use the right context to load the modules correctly for multiversion support. If "require" is not specified as a dependency, then there will likely be an error.
I am curious and still can not explain dependency loop (passed) in this case.
angular.module('mainApp', ['addon.dashboard']).factory('Test', function(){
return {
hello: 'moto'
};
});
angular.module('addon.dashboard', ['mainApp']).controller('Demo', function(Test){
console.log(Test.hello);
});
That is a sample code in my app. The mainApp module require to inject addon.dashboard module. Otherwise, addon.dashboard module require to inject mainApp module.
We can see that it may loop here. But it work in my app. The controller Demo actually output moto into console.
How does angular deal with loop injection like that?
You might want to look into the angular code (especially the loadModules method). Basically there is a HashMap that contains all the modules loaded. If its not in the HashMap, it puts it into that and then goes ahead with initializing the rest of the module. IF its already in the set, it will return immediately.
So, in your case, lets say mainApp gets loaded first. It puts it into loadedModules and the goes to find its dependencies. When it finds addon.dashboard, it finds that mainApp is a dependency, but its already present in loadedModules, so it returns immediately.
Its a lot better if you breakpoint into the "loadModules" method of angular.js