Angular injector error with minified JavaScript - angularjs

I have been struggling to find a solution for this problem:
I am using Angular.js on my site.
I use CoffeeScript to write my JavaScript in Visual Studios 2012. When I save my CoffeeScript - both a minified and un-minified version of the JavaScript file is saved.
While using any minified version of JavaScript files on my webpage I keep getting this error:
Error: $injector:unpr
Unknown Provider
Unknown provider: nProvider <- n
This error results from the $injector being unable to resolve a required dependency. To fix this, make sure the dependency is defined and spelled correctly. For example:
If I don’t use the minified version everything works fine.
Here is how I use angular to declare my App in each JavaScript file
(function() {
var myApp;
myApp = angular.module("myApp", ['uploaddirective']);
myApp.controller("videoController", function($scope, $http, $compile) {
Can anyone help me to resolve this issue?

Use array notation for minification-safe dependency injection:
myApp.controller("videoController", ['$scope', '$http', '$compile', function($scope, $http, $compile) {
Another option is to use build task to automatically annotate injections for you:
// #ngInject
myApp.controller("videoController", function($scope, $http, $compile) {
You will need grunt or gulp plugin for this, like ngAnnotate.
https://docs.angularjs.org/guide/di

When you minifying the above code you will get something like
a.controller("videoController", function(x, y, z) {...
note that $scope, $http, $compile are replaced with x, y, z.
So when angular starts to execute Controller can't find the injectors because $scope, $http, $compile are replaced with x, y, z and there are no inject-able providers as x, y or z, so angular will trigger a error saying Unknown Provider.
solution 1
you can follow Inline Array Annotation as,
myApp.controller("videoController", ['$scope', '$http', '$compile', function($scope, $http, $compile) {...
after minifying this you will get something like
a.controller("videoController", ['$scope', '$http', '$compile', function(x, y, z) {...
minifying process doesn't effect on strings, here angular will use a array with strings that will match the providers. Here angular will match the x with $scope and so on.
solution 2
$inject Property Annotation
var MyController = function($scope, $http, $compile) {
// controller function ...
}
MyController.$inject = ['$scope', '$http', '$compile'];
myApp.controller("videoController", MyController);
additionally check ng-annotate

Related

Different ways to initialize AngularJS Controllers? [duplicate]

I see the following angularjs controller syntax structure all the time.
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location',
function ($scope, $interval, $location)
{
}]);
Why the repetition in the parameter names? Why not just like this
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location',
function ()
{
}]);
or
angular.module('7minWorkout').controller('WorkoutController',
[
function ($scope, $interval, $location)
{
}]);
The array syntax will help you with minification/uglify of your js code.
angular.module('7minWorkout').controller('WorkoutController',
function ($scope, $interval, $location) {
// code here
});
Will be minified and mangled as:
angular.module('7minWorkout').controller('WorkoutController',
function (a, b, c) {
// code here
});
So Angular won't be able to figure out which dependencies to inject
On the other hand, using the array declaration:
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location', function ($scope, $interval, $location) {
// code here
}]);
Will be minified as :
angular.module('7minWorkout').controller('WorkoutController',
['$scope', '$interval', '$location', function (a, b, c) {
// code here
}]);
So Angular will know what a, b and c represent.
There's also another way to inject variables if you use your first example code like below:
WorkoutController.$inject = ['$scope', '$interval', '$location'];
or
angular.module('7minWorkout').controller('WorkoutController', /* #ngInject */
function ($scope, $interval, $location) {
// code here
});
which will create the $inject method mentioned above when the code is annotated.
So, there are mainly four kinds of annotation:
Implicit Annotation - the first example code
Inline Array Annotation - the second example code
$inject Property Annotation - the $inject method
$ngInject Comment Annotation - the #ngInject method
ng-annotate
Tools like ng-annotate let you use implicit dependency annotations in your app and automatically add inline array annotations prior to minifying. If you decide to take this approach, you probably want to use ng-strict-di.
For more information, see AngularJS Developer Guide - Using Strict Dependency Injection.
This "repetion" is to make it safe for minification:
AngularJS - Controllers, Dependencies, and Minification
or you can use following syntax, according to popular angular-styleguide https://github.com/johnpapa/angular-styleguide
angular.module('7minWorkout')
.controller('WorkoutController', WorkoutController);
WorkoutController.$inject = ['$scope', '$interval', '$location'];
function WorkoutController($scope, $interval, $location) {
}
You could write the first version since it just omits the parameters of the function which are also accesible via arguments inside the function. So you would avoid the repition but slicing the arguments property is also not really efficient (compared to just type out the parameters).
As the others answers stated the repition is to make it safe for minification.
The first controller syntax makes it possible to minify/uglify the javascript code with the use of tools like ngmin. I'm not quite sure if the 2nd and 3rd options you have provided are viable options to create a controller, but in any case they will not be minified correctly since the tools will not now what the providers are. I would either suggest to use option 1 or option 3 (without the brackets) to create a controller. Note that option 3 will not be minified correctly by automated tools.
Some Useful information about creating controllers:
AngularJS Developer Guide - Controllers
option3 without brackets
angular.module('7minWorkout').controller('WorkoutController', function ($scope, $interval, $location)
{
//Your Code
});

angular multiple dependency injection

This is a general dependency injection question. Obviously I am doing it wrong.
I am trying to get angular-xeditable working in my app.
https://vitalets.github.io/angular-xeditable/
I've installed it using bower, and added the appropriate script link to my head.
Now I'm trying to inject it.
The docs say
var app = angular.module("app", ["xeditable"]);
so, in my app: I do this:
portalApp.controller('portalController',
['$scope', '$http','$filter', 'xeditable',
function($scope, $http, $filter, xeditable) {
but I get the provide error, meaning it can't find xeditable.
angular.js:13642Error: [$injector:unpr] http://errors.angularjs.org/1.5.6/$injector/unpr?p0=xeditableProvider%20%3C-%20xeditable%20%3C-%20portalController
What am I doing wrong?
OK, duh. It should be
var portalApp = angular.module("portalApp", ['xeditable']);
portalApp.controller('portalController', ['$scope', '$http','$filter', function($scope, $http, $filter) {
I'm still getting lots of errors, but at least not that one.

Error: [ng:areq] Argument 'PreviewController' is not a function, got undefined

I don't know why I am getting this error.
The error I am getting is Error: [ng:areq] Argument 'PreviewController' is not a function, got undefined.
Can someone help me out with this?
Also is there any other way to inject services in a controller?
My code is as follows:
(function() {
'use strict';
angular
.module('MyModule')
.controller('PreviewController' ['$scope','Service1','Service2',
function($scope, $http) {
$http.get("https://api.myjson.com/bins/30e2a")
.success(function(response) {
//Dummy data taken from JSON file
$scope.firstName = response.firstName;
$scope.lastName = response.lastName;
$scope.dateAdded = response.dateAdded;
});
//Functions have been defined. Functionality to be added.
$scope.cancelAndBack = function() {
window.history.back();
};
}]);
}());
You are defining you module incorrectly.
`angular.module('MyModule')`
Is looking for an already initialised module called 'MyModule'.
If you are creating a module from scratch you need to empty array. This would be more module dependencies.
`angular.module('MyModule', [])`
This is how angular knows the difference between, 'create an app' and 'get me an app'.
Finally services. Your using angulars array notation. That is so you can minify your javascript.
angularjs injection system works by name, that's how it can find the dependencies your require, that's also why you can list them in any order you like. However minifying your code changes your variable names and so breaks angular's injection.
The solution is to provide an array of strings telling angular the services you wish to inject and the order they are injected in.
So your array values and properties passed into your controller function must match.
Correct:
.controller('test', ["$scope", "$http", "myService", function( $scope, $http, myService){}]);
Incorrect: (myService won't be defined as its missing from the array)
.controller('test', ["$scope", "$http", function( $scope, $http, myService){}]);

Difference between dependency injection syntaxes in AngularJS

AngularJS supports two slightly different syntaxes for dependency injection
Syntax 1
myModule.controller('myCtrl', function($scope, $http, myService) {
...
...
});
Syntax 2
myModule.controller('myCtrl', ['$scope', '$http', 'myService', function($scope, $http, myService) {
...
...
}]);
Is there a fundamental difference between the two syntaxes?
When to use either of the two syntaxes?
Syntax 2 is called type hinting, if you plan to uglify and mangle your code, angular would still know what services to inject.
After mangling and ugilying:
myModule.controller('myCtrl', ['$scope', '$http', 'myService', function(a, b, c) {
Angular would read the string values of the array provided in order to determine the name of the services a, b, c in order to inject them properly.

having issues with angular minification

I'm having an issue with angular minification when I release. I've redone my controller to have annotations as recommended, but still get the same error:
Error: Unknown provider: nProvider <- n
Here's my first few lines of code for the controller:
var app = angular.module('myApp', ['ngGrid', 'ui.bootstrap.dialog']);
app.controller('MyCtrl', ['$scope', '$dialog', '$http', function ($scope, $dialog, $http){
UPDATE: sorry, I found that there was another function I was using which was taking in $scope as parameter. That was causing the issue. I basically did the same thing to annotate its parameters, and now it works.

Resources