There are set of commonly used providers across my angularjs controllers. Eg. $scope, $rootScope, $http and my customer services. I would like to inject those common providers to all controllers without defining each of them in controllers
Eg,
Instead of,
function HomeCtrl($scope, $rootScope, $http){
.....
}
function MenuCtrl($scope, $rootScope, $http, MyService){
.....
}
Do this,
function HomeCtrl(){
...
// $scope, $rootScope, $http are available here
...
}
function MenuCtrl(MyService){
...
// $scope, $rootScope, $http are available here
...
}
So, in this example $scope, $rootScope, $http are automatically injected to all controllers. But I'm not sure how to do this. Anybody knows a way? Thanks.
I don't think spraying all your controllers with the same dependencies is a good idea. It suggests that the application does not have a good structure and you should probably address this.
Taking your example there are a few things that stand out. You don't need to depend on $scopeand $rootScope, you can get the root scope from $scope using $scope.$root
If you are wrapping logic up in services and reusing code amongst controllers then I would suggest that your controllers don't need to depend on $http, instead move this code into the services that you depend on. Try and name those services appropriately so that you can tell what they do. For instance prefer AccountCreator over something more generic like AccountsService. In fact never name something xxxService the service suffix is a throw a way line that really adds no meaning.
In terms of your actual question, no I don't think there is a way of doing this out of the box. I have some ideas of how you could hack it in, but I think pandoras box should be left locked.
Related
i am new to angularjs,
i have one problem quick replies appreciated.
I Need a variable from one controller to another controller
i don't want to use scope. or Service
how can i do that?
I've taken to implementing models to achieve this kind of functionality. Most commonly I use this to make data sets returned by a web service accessible by multiple screens.
Ex: Say you have an "Accounts" screen that displays course grain information on all accounts but you also want to offer an "Account Details" screen that shows finer grained information. Assuming your collection of accounts contains detailed account information there's no need to suffer an additional web service call from the details screen; merely make the data accessible via a model.
I know its not the best example but you get the point.
Just use in first controller. You need to inject $window service in your controllers.
A reference to the browser's window object. While window is globally
available in JavaScript, it causes testability problems, because it is
a global variable. In angular we always refer to it through the
$window service, so it may be overridden, removed or mocked for
testing.
app.controller("FirstController", ['$scope', '$window', function ($scope, $window) {
$window.my_value = "value";
}]);
And you will get this value in second controller, like
app.controller("SecondController", ['$scope', '$window', function ($scope, $window) {
console.log($window.my_value);
}]);
I have a sidebar that contains a feed from various social medias, along with a service in AngularJS that queries my API for the data. Below is the controller, along with the service (in that order). Why isn't it being executed on page load, and how should I rewrite my code to make it load the data when the page is rendered to the client?
angular.module('HomeCtrl', ['MediaServ']).controller('HomeController', [
'$scope',
'MediaServ',
'$rootScope',
function($scope, $rootScope, MediaServ){
if ($rootScope){
$scope = $rootScope;
}
function handleRes(response){
console.log('hello!');
}
angular.element(document).ready(function () {
$scope.SocialMedia = function(){
MediaServ.feed()
.then(handleRes, handleRes);
}
});
}]);
angular.module('MediaServ', []).service('MediaServ', [
'$http',
function($http){
this.feed = function(){
return $http.get('/api/social/feed');
}
}]);
You can only use things (be it services, factories, filters, etc) from another module if you have first injected that module into your current one. As the code above is written your modules don't know about each other, and so you can't inject MediaServ into HomeController.
To fix it, inject the MediaServ module into the HomeCtrl module like this:
angular.module('HomeCtrl', ['MediaServ'])...
I will also suggest not shortening names (minifiers should shorten things, developers should not) and not using the same name for services and apps. The last one in particular can cause a lot of confusion in a large project. Personally I prefer to name modules things like "media.services" and services "MediaService" but that is personal taste, just keep a clear naming convention so that you always know what is what.
You shouldn't need to wrap your code in angular.element(document).ready(function () { });
The controller will execute on page load automatically, provided it is reference in the page.
So, UncleDave and Erik Honns' responses both led me to realize what was wrong (on top of having a typo in handleRes). Here is my new code:
angular.module('HomeCtrl', ['MediaServ']).controller('HomeController', [
'$scope',
'$rootScope',
'MediaServ',
function($scope, $rootScope, MediaServ){
if ($rootScope){
$scope = $rootScope;
}
function handleRes(response){
if (response.data.tweets){
$scope.SocialMedia = response.data.tweets;
}
}
MediaServ.feed()
.then(handleRes, handleRes);
}]);
It is now working. Thank you everybody for your help. I won't pick a best answer, and instead will let others vote. Feel free to flag this question to be deleted, as the errors were more on my side (kind of being lazy about reading through my code, but I thought that this was one of those Angular things you just kind of have to learn).
Thanks everyone for your help!
I have a service like this
function BroadcastClock($interval, $rootScope){
this.ticker = $interval(function(){
console.log("Tick");
$rootScope.$emit('clockTick');
}, 1000);
}
function ClockService($interval, $rootScope) {
var clock = new BroadcastClock($interval, $rootScope);
}
This does not work unless I change the controller to declare
app.controller('MainCtrl', function($scope, $rootScope, clockService)
In more complex situations (say multiple routes) this adds an extra injection for really no reason. What is the better way to handle this?
Trying to clarify a bit (I don't get the -1 but whatever)
The problem I have here is that I do not need to initialize the service using an actual controller. This service in fact feeds into multiple controllers. The singleton aspect helps me keep a single clock for all controllers.
However, the controllers themselves do not interact with it only via the proxy of the rootScope broadcast so I don't see the need to inject it into the actual controller.
See the plunker for more info it won't work, however, when you change
app.controller('MainCtrl', function($scope, $rootScope)
//To
app.controller('MainCtrl', function($scope, $rootScope, clockService)
it works fine, we are not "doing" anything with the service except listening for broadcasts so it doesn't make any sense to inject.
Because you instantiate BroadcastClock, I think you still should be able to handle it via a service by either exposing it or exposing functions that handles it.
Anyway you can run initializing blocks with .config(), at provider injection time, or in your case .run() at the beginning at application's run time:
app.run(function($interval, $rootScope) {
var clock = new BroadcastClock($interval, $rootScope);
});
Is there a way to provide a non-Angular injection target to the Angular $injector such that Angular constructs like $http, $scope, $location or $q can be injected into it?
//non-angular injection container
var injectionTarget= {
$http:undefined,
$scope:undefined
}
//means to inject into target - this is the part in question
var injector = angular.injector();
injector.injectInto( injectionTarget, ["$http", "$scope"]);
I'm having the hardest time finding any info on how to accomplish what I would assume is a very sought-after feature.
I think that probably the easiest way to do this would be to register your objects as services with the module.
var myObject = {} //Defined elsewhere or here as empty
app.service(‘aReferenceName’, function($http){
myObject.$http = $http;
return myObject;
});
This would have the double effect of setting the properties you want on your object, and making it accessible from angular as needed. It's also a pretty simple block of code. Note the implication though that as a service it would be a singleton from angular's perspective. If you need to do it as a class with many instances, you'll be wanting a factory.
I'm aware that for the purposes of minification and obfuscation we should always use the $injector (by way of controllerName.$inject = ['$service', '$service2']) to specify the actual service names that are required.
If I write a custom service that relies on other services, however, can/should I do the same thing? The only examples I can find for using the .$inject method are called on Controllers.
If I am doing
myModule.factory('myService', function($rootScope, anotherService) {
return {
foo: 'bar'
});
Should I append this?
myService.$inject = ['$rootScope', 'anotherService'];
Or perhaps it's applied to the module as a whole then?
myModule.$inject = ['$rootScope', 'anotherService'];
...But maybe in that case, the module is already keeping track of its services, and hence minification is not a concern?
Check the dependency injection guide, section Inline Annotation.
The following is also a valid syntax, and it is safe for minification:
myModule.factory('myService', ['$rootScope', 'anotherService',
function($rootScope, anotherService) {
....
}]);