AngularJS - is there any dependency injection container? - angularjs

Have a look into my AngularJS controller:
MyApp.controller('MyAppController', function($scope, $http, $filter,
$location, $window, FileUploader) {
// ...
});
Is there any Dependency Injection Container or current approach looks fine?

It looks fine, but if you plan on minifying your code later on you will need to write the code like this instead so that Angular knows what to inject:
MyApp.controller('MyAppController', ['$scope', '$http', '$filter', '$location', '$window', 'FileUploader', function($scope, $http, $filter, $location, $window, FileUploader) {
...
}]);
If you use Gulp, there is a plugin ng-annotate which I've found very useful and it takes care of this extra code for you. Saves you from having to write everything twice.

Angularjs takes care of the dependency injection for you, but to put the dependencies in an array like below, explicitly states what should be injected. If the parameters in the function are minified to 'a', or 'b', the array let's angularjs know what to inject.
MyApp.controller('MyAppController', ['$scope', '$http', '$filter', '$location', '$window', 'FileUploader', function($scope, $http, $filter, $location, $window, FileUploader) {
...
}])

Related

Grouping Angular services together to inject them in multiple Controllers

I am currently trying to refactor everything on our company following best practices and JohnPapa's style guide, which means that among other things, I am supposed to switch from setTimeout to $timeout, setInterval to $interval, etc.
However, I find it tiring, messy, and counter-intuitive to have to inject those services every single time. This results in long repetitive controller declarations where half of the elements are useless and obvious.
angular.module('myModule',[])
.controller('MyController', ['$scope', '$http', '$timeout', '$interval', MyController])
.controller('MyController2', ['$scope', '$http', '$timeout', '$interval', MyController2])
.controller('MyController3', ['$scope', '$http', '$timeout', '$interval', MyController3])
I find this ugly, and a pain to maintain; this is the reason why I've always favored setTimeout over $timeout, but now I'm trying to improve.
Would there be a way to "mass inject" services?
For example something such as:
var baseServices = {
http: $http,
scope: $scope,
timeout: $timeout,
interval: $interval,
};
angular.module('myModule',[])
.controller('MyController', ['baseServices', MyController])
.controller('MyController2', ['baseServices', MyController2])
.controller('MyController3', ['baseServices', MyController3])
var MyController = function(baseServices){
baseServices.$timeout(...);
}
Is this something remotely possible?
Maybe you could use a factory to group all these services and use it from your controller
angular.module('myModule',[])
.controller('MyController', ['baseServices', MyController])
angularApp.factory('baseServices', baseServices );
function baseServices ($scope, $http, $timeout, $interval) {
return {
scope: $scope,
http: $http,
timeout: $timeout,
interval: $interval
};
}

AngularJS $parse TypeError: object is not a function

I have stripped my app down to the bare bones but I keep getting this error when using $parse: TypeError: object is not a function
What is wrong? What am I missing?
Seems to work fine in this plunker: http://plnkr.co/edit/WrXv9hT5YA0xYcLLvyDb
Could parse be conflicting with some other module?
Weirder still - it actually does change the value of $scope.modal.on! Even though it appears to die before hand...
/* Controllers */
//var MyApp = angular.module('MyApp', ['ngSanitize', 'ui.bootstrap', 'ui.sortable']);
var MyApp = angular.module('MyApp', ['ngSanitize', 'ui.bootstrap']);
MyApp.controller('MyController', ['$scope', '$http', '$modal', '$parse', function($scope, $http, $parse, $modal, $log) {
$scope.modal = {
open : false,
tplfile : null,
toggle : function(){
this.open = !this.open;
if(this.open) angular.element('body').addClass('modal-open');
else angular.element('body').removeClass('modal-open');
}
};
var modal = $parse('modal.open');
modal.assign($scope, true);
}]);
You passed in your dependencies in the incorrect order. The dependencies to the function have to match exactly the order in the array.
MyApp.controller('MyController',
['$scope', '$http', '$modal', '$parse', function
($scope, $http, $parse, $modal, $log) {
If you swap $parse and $modal in your controller declaration, your error will go away. Also, you are missing $log, if you try to use that dependency you will get an error as well.
['$scope', '$http', '$modal', '$parse', function($scope, $http, $parse, $modal,
The $parse and $modal are interchanged.
Please correct the order and it will work :)
It should be
MyApp.controller('MyController', ['$scope', '$http', '$modal', '$parse', '$log', function($scope, $http, $modal, $parse, $log) {

Angularjs - injecting dependencies into multiple controllers

I'm still quite new to angular, and have been building a simple CRM application. For a single resource (restful API resource) I have 3-4 routes and controllers defined in my angular application. Now, there are a set of services and modules that I repeatedly have to inject into each controller. I understand that each controller will have it's own instance of scope and shared instance of factory/services but is there a way to centrally define dependencies for multiple controllers?
In the example below, $modal, growl, configuration, $scope are injected into all 3 controllers, I'd like to define that only once.
Listings Controller
myApp.controller('VenueListCtrl', ['$scope', '$http', 'configuration', '$modal', 'growl',
function ($scope, $http, configuration, $modal, growl) {
}
]);
Create/New Controller
myApp.controller('VenueCreateCtrl', ['$scope', '$http', '$location', 'configuration',
function ($scope, $http, $location, configuration) {
}
]);
Details Controller
myApp.controller('VenueDetailCtrl', ['$scope', '$routeParams', '$http', '$modal', 'configuration',
function ($scope, $routeParams, $http, $modal, configuration) {
}
]);
Best you can do is: use not-anonymous function declaration of controllers:
var depsToInject = ['$scope', 'growl', 'configuration', '$modal'];
myApp.controller('Ctrl1' , Ctrl1);
Ctrl1.$inject = depsToInject ;
function Ctrl1($scope, growl, configuration, $modal) {
// ...
}
myApp.controller('Ctrl2' , Ctrl2);
Ctrl2.$inject = depsToInject ;
function Ctrl1($scope, growl, configuration, $modal) {
// ...
}
etc. But that does not fully unify declaration and I don't think there is a better way. However you can try from the other side and wrap your dependencies with another dependency, but I don't like this way either.

AngularJS 1.3.0 + TypeScript controller definition issue

In our application we use the "controller as" syntax:
<div class="workspace-header" ng-controller="LoginController as loginCtl">
To define the LoginController, we define it as a TypeScript class:
class LoginController {
// variables here
constructor($rootScope, $http, $location, $cookieStore, AuthService, AUTH_EVENTS, localStorageService) {
// set variables
this.$rootScope.$on(AUTH_EVENTS.logoutSuccess, () => {
this.logout();
});
}
public login(credentials: any): void {
this.AuthService.login(credentials).then(() => {
// login success
}, () => {
// login failed
});
}
public logout() {
}
}
and instantiate it this way:
.controller('LoginController', ['$rootScope', '$http', '$location', '$cookieStore', 'AuthService', 'AUTH_EVENTS', 'localStorageService',
($rootScope, $http, $location, $cookieStore, AuthService, AUTH_EVENTS, localStorageService) =>
new LoginController($rootScope, $http, $location, $cookieStore, AuthService, AUTH_EVENTS, localStorageService);
])
After upgrading to AngularJS 1.3.0 this does not work at all. The "controller as" syntax is completely broken (when used in this fashion). We define a form on the page with ng-submit:
<form name="loginForm" ng-submit="loginCtl.login(dc.credentials)" novalidate>
... fields here
<button type="submit">Login</button>
</form>
The loginCtl.login() does nothing, and no errors are output to the console.
After a lot of debugging and some digging, I believe the breaking change in AngularJS is this:
https://github.com/angular/angular.js/issues/8876
https://github.com/angular/angular.js/pull/8882 (added note to documentation)
If I modify my controller as such:
.controller('LoginController', ['$rootScope', '$http', '$location', '$cookieStore', 'AuthService', 'AUTH_EVENTS', 'localStorageService',
function ($rootScope, $http, $location, $cookieStore, AuthService, AUTH_EVENTS, localStorageService) {
var loginCtrl = new LoginController($rootScope, $http, $location, $cookieStore, AuthService, AUTH_EVENTS, localStorageService);
// since controllers always return 'this', extend 'this' with the controllers
// properties and it's prototype's properties
_.extend(this, loginCtrl);
_.extend(this, loginCtrl["__proto__"]);
}
])
Then I can get it working, but this seems messy (and I'm not sure if I would have to chain up prototypes in case of superclasses).
Has anyone else run into this and have a better approach for defining these classes in TypeScript?
As PSL said, this is the problem:
.controller('LoginController', ['$rootScope', '$http', '$location', '$cookieStore', 'AuthService', 'AUTH_EVENTS', 'localStorageService',
($rootScope, $http, $location, $cookieStore, AuthService, AUTH_EVENTS, localStorageService) =>
new LoginController($rootScope, $http, $location, $cookieStore, AuthService, AUTH_EVENTS, localStorageService);
])
You can simply use LoginController in place of the giant arrow function.
See this comment in the issue you linked about how returning an object is incorrect; the function needs to be something that works when the new operator is used on it.
As PSL said but with $inject... I posed a similar question Angular 1.3 breaking changes - scope set but reset before $apply
I've put my answer here: http://plnkr.co/edit/NMPXFd67WLXHjhrfync2
//other dependencies deleted for brevity
.controller('LoginController', ['$scope', LoginController]);
LoginController.$inject = ['$scope'];

how to pass multiple services in controller in angularjs?

I have a service called authService. I call it from the Logincontroller as follows :
angular.module('myApp').controller('LoginController',function($q, $scope, $location,$routeParams, $window, authService) {//some code here});
this works fine.
Now I have another service called regService which is like :
angular.module('myApp').factory('regService ', function ($window, $q, $rootScope) {//some code here});
Now in LoginController how do I call functions from regService ?
Both existing answers are technically correct, but if you decide to minify/uglify your code anytime in the future, those solutions will eventually break.
To prevent this, John Papas AngularJS style guide favors the use of the $inject service in Y091 like so :
angular.module('myApp').controller('LoginController', LoginCtrl);
LoginCtrl.$inject = ['$q', '$scope', '$location', '$routeParams', '$window', 'authService', 'regService'];
function LoginCtrl($q, $scope, $location, $routeParams, $window, authService, regService) {
//some code here
}
Just do it like authService, you just need to add regService. AngularJS will automatically bind the service based on name. You might want to understand more about Dependency Injection - https://docs.angularjs.org/guide/di
angular.module('myApp').controller('LoginController',function($q, $scope, $location,$routeParams, $window, authService, regService) {//some code here});
Just do:
angular.module('myApp')
.controller('LoginController', function($q, $scope, $location, $routeParams, $window, authService, regService) {
});

Resources