how to limit dependency injections in angularjs - angularjs

I used dependency injections in my controllers as follows.
.controller('deals_list', function ($scope, global, config, services, dealService, pagination) {
Now the app was growed. Dependencies are growing too. I want limit these injections. So is there a way to limit those with global injections or something?
What kind of procedure actually should I follow?

var myApp= angular.module('myApp', []);
myApp.run(function ($rootScope, $location, $http, $timeout, YourService) {
$rootScope.MyService = YourService;
}
Used it into controller :
myApp.controller('YouCtrl', ['$scope', function ($scope) {
// scope inherits from root scope
$scope.MyService.doSomething();
}]);

What i believe you can do is to create a service that contains all the services that you want to use. The global service is like a facade into your real service.
The option then are to create on global service with all dependencies included. Or multiple facade service which group these services
app.service("Configurations",function(global,config) {
this.global=global;
this.standard=config;
});
app.service("AppServices",function(services, dealService, pagination) {
this.services=services;
// other assigments
});
Now you can inject Configurations and AppServices
This at least gives some visibility into what your controllers are dependent upon.

Related

How to do dependency injection in multiple controller in a single step

I'm using ionic1 and I have multiple controller each one is for different page.
Consider the following injections:
.controller('login', function($scope, $http, $location, $state,$rootScope , auth,$timeout)
.controller('Home', function($scope, $rootScope, $http, $state,$location, $ionicNavBarDelegate, $timeout, auth, getData)
So on I have about 10 of them.
Most of the injections are common to all the controllers such as $scope,$rootScope and few others.
So I want to know if there is a one liner to inject all the dependencies in one go.
You could create a factory which returns some of the most used dependencies.
Something like this:
angular
.module('app')
.factory('common', common);
common.$inject = ['$rootScope', '$http', '$state'];
function common($rootScope, $http, $state) {
var service = {
$rootScope: $rootScope,
$http: $http,
$state: $state
};
return service;
}
then you just need to include the common service in your controller and use it like this: common.$rootScope.
Hope this helps :)
Edit
As #estus said in the comments, with $scope it would fail because $scope is a local dependency and not available in services/factories. This should not be an issue since I would recommend to avoid $scope as far as possible (use controllerAs syntax)
Injecting all dependencies contradicts the concept of dependency injection (besides the fact that controllers can have local dependencies). A dependency is what a controller depends on.
If there are several controllers that have matching dependencies, they can inherit base controller. If child controllers should have their own dependencies, this can be done with base class that automatically assigns dependencies to controller instance. Controller inheritance works best with ES6 classes:
class BaseController {
static get $inject() {
return ['$rootScope', '$scope', '$timeout'];
}
constructor(...deps) {
this.constructor.$inject.forEach((depName, i) => {
this[depName] = deps[i];
});
}
}
class SomeController extends BaseController {
static get $inject() {
return [...super.$inject, 'some'];
}
constructor(...deps) {
super(...deps);
...
}
}
app.controller('SomeController', SomeController);

Conditionally inject angular module dependency

I'm new to angular and have the following code.
angular.module('MyApp')
.controller('loginController', ['$scope', '$http', 'conditionalDependency',
function ($scope, $http, conditionalDependency{
}
I would like to have conditionalDependency loaded conditionally. Something like this
if(true)
{
//add conditionalDependency
}
How can this be done. I've seen this post . However, my requirement is that I have the dependency specified in function
Thanks in advance.
Not quite clear as to why you would have to have it in a named function like in your example but...
If you need conditional dependencies, I would suggest taking a look at the following:
Conditional injection of a service in AngularJS
I've used this method in a couple niche scenarios and it works quite well.
EXAMPLE:
angular.module('myApp').controller('loginController',
['$injector', '$scope', '$http',
function($injector, $scope, $http) {
var service;
if (something) {
service = $injector.get('myService');
}
});
You can use it even without injecting injector in your controller
if(something){
var injector = angular.element(document).injector();
var myService = injector.get('myService')
}
Use:
angular.injector().get('conditionalDep');
You can inject $injector once to your file and call $injector.get('dep');

Is there a way to resolve a service without routeProvider?

I have a controller that it's not defined on $routeProvider. I use it internally inside other controllers. Is there a way to resolve a dependency without the $routeProvider?
==
My friend below asked for more information, here it goes:
I don't want to call promise methods (basically then) inside my controllers. But I have dependencies on some of this controllers that are promises. When a controller is defined on the $routeProvider, I can resolve its dependencies. But how about the controllers that are not defined there? Is there any solution? Follows an example:
My $routeProvider doesn't map this controller and this is the code I have to do because my Cart is a promise:
.controller('MyCtrl', ['$scope', 'Cart',
function ($scope, Cart) {
Cart.then(function(res) {
$scope.cart = res.query();
});
This is the code I'd like to do:
.controller('MyCtrl', ['$scope', 'Cart',
function ($scope, Cart) {
$scope.cart = Cart.query();
});
if you mean resolve -- dependency injection -- yes. below should work:
element.injector().invoke(['dep1','dep2', function(dep1,dep2){}])
...
the idea is to retrieve the current injector, and use invoke().

$window on ngClick directive

Why this doesn't work ?
Since angular expression doesn't have access to window object, i've used $window, however the below doesn't work.
<button ng-click="$window.alert('Hi There')">Hi There</button>
Angular expressions do not have access to global variables like
window, document or location. This restriction is intentional. It
prevents accidental access to the global state – a common source of
subtle bugs.
A template only has access to variables that are put on its $scope. If you need to access anything on $window from your template you'll need to inject $window into your controller and assign it to $scope there.
For example
angular.module('app').controller('Controller',
['$scope', '$window', function($scope, $window) {
$scope.$window = $window;
}]);
As pointed out in the comments, you probably don't want to expose the entire $window wrapper to your template so a better approach is to use a helper function on $scope.
ng-click="greet('Hi There')"
angular.module('app').controller('Controller',
['$scope', '$window', function($scope, $window) {
$scope.greet = function(message) {
$window.alert(message);
};
}]);
You can only call services in your controllers through scope (this is the idea of separating non-UI logic from the template)
See How to call a service function in AngularJS ng-click (or ng-change, ...)?
$window is a service, and like other services that don't relate directly to the view, they are not accessible in the templates.
angular.module('app').controller('Controller',
['$scope', '$window', function($scope, $window) {
$scope.alert=$window.alert
}]);

Injecting a service into another service in angularJS

Is it possible to inject one service into another service in angularJS?
Yes. follow the regular injection rule in angularjs.
app.service('service1', function(){});
//Inject service1 into service2
app.service('service2',function(service1){});
Thanks to #simon. It is better to use Array injection to avoid minifying problem.
app.service('service2',['service1', function(service1) {}]);
Yes. Like this (this is a provider, but same thing applies)
module.provider('SomeService', function () {
this.$get = ['$q','$db','$rootScope', '$timeout',
function($q,$db,$rootScope, $timeout) {
return reval;
}
});
In this example, $db is a service declared elsewhere in the app and
injected into the provider's $get function.
In order to avoid any confusion, I think it is also worth mentioning that if you are using any other services (e.g. $http, $cookies, $state) in your childService, then you also need to explicitly declare them.
e.g.
function() {
var childService = function($http, $cookies, parentService) {
// Methods inherited
this.method1Inherited = parentService.method1();
this.method2Inherited = parentService.method2();
// You can always add more functionality to your child service
angular.module("app").service("childService", ["$http", "$cookies", "parentService", childService]);
}());
You can either declare the services you are using inside your child in an array and then they get injected automatically, or inject them separately with the $inject annotation:
childService.$inject = ["$http", "$cookies", "parentService"];
angular.module("app").service("childService ", childService );

Resources