Possible to inject a complete module in Angular? - angularjs

Is it possible to inject a complete module into a controller instead of injecting separately each services?
For example:
var app = angular.module('myApp', ['myApp.core']);
angular.module('myApp.core', [])
.factory('ABService', function() {
return {
getA: function() {
return 'A';
},
getB: function() {
return 'B';
}
}
})
.factory('AnotherService', function() {
return {
calc: function(a, b) {
return a + b;
}
}
})
app.controller('MainCtrl', function($scope, 'myApp.core') {
ABService.getA();
AnotherService.calc(2, 2);
});
Instead of
app.controller('MainCtrl', function($scope, ABService, AnotherService) {
ABService.getA();
AnotherService.calc(2, 2);
});

No.
Why?
You can't inject module to a controller, lets look at this image:
What we can see from this: is that a module is a sort of component it self, which is built on top of controllers, directives, services and filters, and so on.
The real questions coming out of this:
Can a module be without a controller?
Yes.
The is no necessity for a controller in a module. it pretty much depends on the job of that module, it could totally be made out of services and directives.
Can we inject a service from a module to another module's controller?
Yes.
You totally can, this practice is usually being used when you are trying to build a Store site but could happen in much more cases.
You would probably have the module that contains: browsing the items, searching through items, and so on.
But how would you create the cart in that manner?
Let's see: the cart looks like a component to me.
Why?
Because it is something that I would want to test separately from the rest of the code,
It's also built like a component that should have it's own unique services, and directives, and from my point of view should be derived from the rest of the application.
So we should build a module!
Exactly, and whenever you are trying to USE the cart from the store's module's controller, you could simply inject the service that helped you build the cart from that module, and you could apply rules to the store's controller.
In terms of your question:
What I think you are trying to do, or atleast what is possible to do in your situation:
To inject a service from module a into a controller located in module b, there is no need to "inject" the full module into the controller, it doesn't quite make sense.
I hope I explained it as good as it sounds in my head :).

No, but you could wrap your services into one "God" service if you really wanted to (I personally wouldn't recommend it)
angular.module('myApp.core', [])
.factory('ABService', function() {
return {
getA: function() {
return 'A';
},
getB: function() {
return 'B';
}
}
})
.factory('AnotherService', function() {
return {
calc: function(a, b) {
return a + b;
}
}
})
.factory('GodService', function(ABService, AnotherService) {
return {
ABService: ABService,
AnotherService: AnotherService
}
})
Then you could inject the GodService and call ABService and AnotherService off of it.

Related

Can I extract controller functions to external files?

My controller is getting somewhat busy and finding the function that I'm looking for is becoming cumbersome. I'd like to have individual files for some of my controller functions. How can I achieve this? Is there something like ng-include for the controller to use?
You might use the mixin pattern. This allows you to extend your controllers with other controllers. As a result you have now two different controllers, while both get executed at the same time:
app.controller('AnyController', ['$scope'
function ($scope) {
return {
myFunction: function() {
// do something
}
}
}
]);
app.controller('MyMainController', ['$scope'
function ($scope) {
var anyThing = $controller('AnyController as anyThing',{$scope: $scope}),
$scope.anyThing = function() {
// those two options are now both valid:
anyThing.myFunction();
$scope.anyThing.myFunction();
}
}
]);
Now you are able to move your seperate controllers into different files.

AngularJs - Best way to include my service inside every controller?

I'm building a small two-language app with the use of angular-translate. I want to have a language switcher in every view (controller). I'm trying to figure out how to put the code responsible for language switching into every controller. The code looks like this:
var langSwitch = $Scope.setLang = function (langKey) {
$translate.use(langKey);
};
So far I've figured that I can create a factory that looks like this:
app.factory('langSwitch', function ($rootScope, $translate) {
var langSwitch = $rootScope.setLang = function (langKey) {
$translate.use(langKey);
};
return langSwitch;
});
and inject it into controllers in this maner:
app.controller('HomeCtrl', function (langSwitch) {
// normal controller code here
});
This works but 1) I'm using $rootScope and I have a feeling this is bad practice & 2) jsHint screams that "langSwitch" is not defined. Maybe there is a simpler way to make the function global without putting it into every controller?
I'm still pretty new to Angular so don't scream at me :) Thanks.
edit
My view:
<button ng-click="setLang('en_GB')">English</button>
<button ng-click="setLang('pl_PL')">Polish</button>
Although you got the idea, you overcomplicated things a bit. You could declare the service as follows:
app.service('langSwitch', function ($translate) {
this.setLang = function (langKey) {
$translate.use(langKey);
};
});
And then inject langSwitch in the controller responsible for lang switching, as you already did. No need to inject $rootScope in the service.
You don't need $rootScope indeed unless you need to process some global events in your application. All services and factories in angular are singletons by default. That means once it created, it will be passed as the same instance in every place it is declared as a dependency. So if you want to share data and functionality between different controllers - the services will suit fine. You can change your factory code to:
app.factory('langSwitch', function($translate) {
return {
setLang: function(langKey) {
$trasnlate.use(langKey);
};
};
});

AngularJS Services - using in Controller

I'm building a pretty simple app where I have a GlobalController (on body element), and will have another sub-controller below. This is a templated site with multiple, physical pages such that the sub-controller will be different, but at most there will only be a top-level Global one and a single sub-one.
I'm trying to make global functions that any sub-controller can use to run code that each needs to run without having to duplicate the functionality in each sub-controller.
One way I could do this would be to include $rootScope and then emit() messages to the GlobalController who is listening for them using $on().
I gather this is not a "good" way to do this. Rather, I've learned that it's better to use a service for this. I'm now stuck on how to implement this service.
I currently have a Global Controller like so:
var globalModule = angular.module('DoSquareStuff', ["ngRoute","list", "savings-video"]);
// there will be a long list of modules that will be added after "savings-video"
globalModule.factory('squareMgr', function() {
var squares = SUYS.squares; // global obj with earned[] and placed[]
return {
getSquaresEarned: function() {
return squares.earned;
},
getSquaresPlaced: function() {
return squares.placed;
},
setThisSquareEarned: function(value) {
squares.earned.push(value);
},
setThisSquarePlaced: function(value) {
squares.placed.push(value);
},
earnedThisSquare: function(squareNum) {
return ~squares.earned.indexOf(squareNum);
},
placedThisSquare: function(squareNum) {
return ~squares.placed.indexOf(squareNum);
}
}
});
globalModule.controller('GlobalController', function($scope, $squareMgr){
// this would be easy... but it doesn't work
// $rootScope.$on('signal.missionComplete', function (event, missionId) {
// console.log("parentScope receive notice that mission " + missionId + " is complete.");
// });
log('GlobalController loaded');
// log($squareMgr.getSquaresEarned()); //broken
});
Then, reading the docs, I tried:
globalModule.controller('GlobalController', ['squareMgr', function($squareMgr){
// but then how do I get $scope in there?
log('GlobalController loaded');
// log($squareMgr.getSquaresEarned());
}]);
In your last code block, you need to inject $scope as well. You can inject any number of services that you need:
globalModule.controller('GlobalController', ['squareMgr', '$scope',
function($squareMgr, scope){
// but then how do I get $scope in there?
log('GlobalController loaded');
// log($squareMgr.getSquaresEarned());
}]);
And a minor point, I wouldn't put a $ in front of squareMgr, the $ implies it is a built in angular service.
Try
globalModule.controller('GlobalController', ['squareMgr', '$scope', function($scope, squareMgr){ .....
The $ sign is used to differentiate between Angular services and your own

Inject a config in AngularJS

I have a config that I'd like to be able to inject into Angular services, directives, etc. What is the best way to go about doing this?
I was playing with the idea of making config module:
'use strict';
angular.module('config', [])
But I wasn't sure how to construct the object literal that would be the actual config object that gets injected:
angular.module('myModule', ['ngResource', 'config'])
.factory('myservice', function ($resource) {
return $resource(config.myservice,{}, {
// whatever
})
});
Would it be okay to just expose config as a service and inject that?
I would say, the strategy varies, depending on what sort of config you have, but you have several options:
Module wide constants
If you only need several constants, you can use .value(), like this:
var app;
app = angular.module("my.angular.module", []);
app.value("baseUrl", "http://myrestservice.com/api/v1");
//injecting the value
app.controller("MyCtrl", ['baseUrl', function (baseUrl) {
console.log(baseUrl); // => "http://myrestservice.com/api/v1"
}]);
See a more detailed answer here.
Fetching the config/config service
What i personally like to do is fetch my configuration from somewhere else via a service just as normal. It doesn't matter, if this is a remote location or just static information.
var app;
app = angular.module("my.angular.config", []);
app.service('Configuration', [function() {
return {
getbaseUrl: function() { return "http://myrestservice.com/api/v1" },
getConfig: function() {
return {
answer: 42,
question: "??"
}
}
}
}]):
EDIT: example with an external fetch:
var app;
app = angular.module('my.module.config', []);
app.factory('ConfigurationData', ['$http', '$q', function(http, q) {
var deferredConfig = q.defer();
//error handling ommited
http.get('http://remote.local/config.json').success(function(data) {
return deferredConfig.resolve(data);
});
return {
getConfig: function() {
return deferredConfig.promise;
}
};
}]);
With this service, you can inject your config into other services, however, you can run into timing issues, as you have to inject and resolve the promise given by the service before anything you want to do with the config:
var app;
app = angular.module("my.other.module", ['my.module.config']);
app.factory('MyAwesomeService', ['ConfigurationData', function(config) {
config.getConfig().then(function(config) {
//do something with your config.
});
}]);
You get a bit more fine control here, as you can react to different inputs. Again, it depends on your use case. You can use a factory here if you need additional logic for structuring the configuration.
Lastly, if you want even more control over configuration, you can make a
Custom Provider
Providers can be pretty useful, but i think they are a bit harder to design. Considering a baseUrl from the configuration needed for your app to work, you could write a provider for the service needing the value of the baseUrl like this:
var app;
app = angular.module('my.angular.module', []);
app.provider("RestServiceProvider", function(){
this.baseUrl = 'http://restservice.com';
this.$get = function() {
var baseUrl = this.baseUrl;
return {
getBaseUrl: function() { return this.baseUrl; }
}
};
this.setBaseUrl = function(url) {
this.baseUrl = url;
};
});
This lets you do cool stuff in the config phase of your application:
app.config(['RestserviceProvider', function(restServiceProvider) {
restServiceProvider.setBaseUrl('http://wwww.myotherrestservice.com');
}]);
Every instance you fetch in a service/controller/etc. of RestService will now have the baseUrl set from the config phase from the moment you inject it.
For a more detailed overview, i suggest this gist.
Creating a stand-alone module that only has a service or a directive (or both) is a great way to make application-independent angular code. If you do this you can easily just take that .js file and plop it into any project, and all you need to do is inject it into your applications and it just works.
So doing something like:
angular.module('config', [])
.factory('config', function() {
return {
theme : 'nighttime',
cursor : 'sword',
...
};
});
Then you can just inject it into any application like so:
angular.module('myModule', ['config'])
.factory('myservice', function (config) {
var theme = config.theme;
var cursor = config.cursor;
// do stuff with night-time swords!
});
This is actually how the angular-ui team package all their directives, each directive is contained within its own module, which makes it easy for others to just take that code and reuse it in all their apps.

AngularJS - what are the major differences in the different ways to declare a service in angular?

I am working on an angularJS app and I am trying to stick with the most efficient and widely accepted styles of development in AngularJs.
Currently, I am using this way of declaring my services like so:
app.factory('MyService', function() {
/* ... */
function doSomething(){
console.log('I just did something');
}
function iAmNotVisible(){
console.log('I am not accessible from the outside');
}
/* ... */
return{
doSomething: doSomething
};
});
However, there are numerous examples out there and I am not quite sure which design style to follow. Can someone with extensive knowledge about services explain the reason why a certain style is more relevant than another?
Is what I am doing useful in any way other than restricting the access to certain functions in my service?
I would suggest you layout your factory or service as they do in the angular-seed app, except that app annoyingly only uses value in the services.js boilerplate. However you can adapt the layout they use for controllers, directives and filters.
'use strict';
/* Filters */
angular.module('myApp.filters', []).
filter('interpolate', ['version', function(version) {
return function(text) {
return String(text).replace(/\%VERSION\%/mg, version);
}
}]);
Which means for a service you would do:
'use strict';
/* Services */
angular.module('myApp.filters', []).
service('myservice', ['provider1', 'provider2', function(provider1, provider2) {
this.foo = function() {
return 'foo';
};
}]).
factory('myfactoryprovider', ['myservice', function(myservice) {
return "whatever";
}]);
This has more boilerplate than you absolutely need, but it is minification safe and keeps your namespaces clean.
Than all you have to do is decide which of const, value, factory or service is most appropriate. Use service if you want to create a single object: it gets called as a constructor so you just assign any methods to this and everything will share the same object. Use factory if you want full control over whether or not an object is created though it is still only called once. Use value to return a simple value, use const for values you can use within config.
I don't believe there's an accepted standard but I myself follow this convention:
var myServiceFn = function (rootScope, http) { ... };
...
app.factory('MyService', ['$rootScope', '$http', myServiceFn]);
I feel like this is cleaner than defining the function inline and also allows for proper injection if I ever decide to minify my files. (see http://docs.angularjs.org/tutorial/step_05).
As an example, I've been defining services within modules like so:
angular.module('userModule', [])
.service('userService', function() {
this.user = null;
this.getUser = function() {
return this.user;
};
this.userIsNull = function() {
return (this.user === null);
};
this.signout = function() {
this.user = null;
};
})
I think it is more clear to use the .service rather than the .factory?

Resources