Angular build not working on server - javascript

I am trying to run my AngularJS front-end on server. I am using Yeoman to build the app. I upload the very basic hello world app and I get plain HTML text withou JavaScript loaded. Console in Chrome says this:
Error: Unknown provider: aProvider <- a
at Error (<anonymous>)
at http://../scripts/vendor/d10639ae.angular.js:2627:15
at Object.getService [as get] (http://../scripts/vendor/d10639ae.angular.js:2755:39)
at http://../scripts/vendor/d10639ae.angular.js:2632:45
at getService (http://../scripts/vendor/d10639ae.angular.js:2755:39)
at invoke (http://../scripts/vendor/d10639ae.angular.js:2773:13)
at Object.instantiate (http://../scripts/vendor/d10639ae.angular.js:2805:23)
at http://../scripts/vendor/d10639ae.angular.js:4620:24
at update (http://../scripts/vendor/d10639ae.angular.js:13692:26)
at http://../scripts/vendor/d10639ae.angular.js:8002:24 d10639ae.angular.js:5526
Anybody experiencing the same and knows the way out?
EDIT:
'use strict';
yoAngApp.controller('MainCtrl',['$scope', '$window', function($scope, $window) {
$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Testacular'
];
$scope.records = [{ title : 'one' }, { title : 'two' }, { title : 'three' }, { title : 'four' }];
$scope.greet = function() {
($window.mockWindow || $window).alert('Hello ' + $scope.name);
}
}]
);

I'm pretty sure that you have used code minifier for production server, am I right?
Anyways, the folks from Angular Js made pretty clear that using minifier can mess up Dependency Injection if it's not done properly. Why this happens? Have a look:
Dependency Injection vs. Code Minifier
function MyController($scope, $log) { ... }
In the snippet above you are making use of implicit DI. Angular sees variable $scope and tries to match it with any managed dependency. In this example it will match it to the $scope object.
This, however, will not work after code minifying, as the result will look somehow like this:
function a(b, c) { ... }
Since variable and function names were minified, Angular cannot know what exactly an "a" is.
Solution
Use explicit Dependency Injection configuration.
var MyController = function($scope, $log) { ... }
MyController.$inject = ['$scope', '$log'];
In this snippet you are defining which dependencies should be resolved by attaching array of their names to special property of controller (or service) called $inject. Now Angular will know that it should resolve $scope and pass it as first parameter to MyController. Then it will resolve $log and pass it as second parameter.
It's all possible because minifiers won't modify the contents of string variables.

As #ƁukaszBachman suggested, you may use $inject annotation or you may use Inline Annotation if you want to:
Keep your dependency annotations close to your function definitions (for better readability).
Stay away from polluting global namespace.
app.controller('UsersController',
[
'$scope', 'UserService', '$location', '$routeParams',
function($scope, User, $location, $routeParams) {
$scope.user = User.get({id: $routeParams.id});
...
}
]
);

Related

How to use constants defined in one file in another in angularjs

Well I have seen couple of questions in StackOverFlow related to this but couldn't find proper answer.
Say in my app.js file I have defined a constants object which basically has controllers names. As I use "ui-router" I want to attach Controllers to views on state change.
app.js
var app = angular.module('myApp', ['ui.router']);
app.constant('CONTROLLER', {
ONE: 'ControllerOne',
TWO: 'ControllerTwo'
});
Now I want to use those constants to define Controller names in other file, say controller.js. Illustrating couple of ways which I tried but dint work for me.
controller.js
var app = angular.module('myApp', ['CONTROLLER']);
app.controller(CONTROLLER.ONE, ['$scope', 'myFactory', function ($scope, myFactory) {
$scope.result = myFactory.someAPI();
}]);
ERROR -> Uncaught ReferenceError: CONTROLLER is not defined
Even I tried injecting that constant module in Controller which gave same error.
var app = angular.module('myApp', ['CONTROLLER']);
app.controller(CONTROLLER.ONE, ['$scope', 'myFactory', 'CONTROLLER', function ($scope, myFactory, CONTROLLER) {
$scope.result = myFactory.someAPI();
}]);
I know that second way is wrong. As I define controller names in my main app.js file and use those constants to attach controllers to views during state change.
I want reuse those constants to define controllers names too.
I may be doing something wrong. Any suggestions ?
Your code shows that you have correctly injected the CONTROLLER constant into the controller constructor function.
var app = angular.module('myApp', ['CONTROLLER']);
app.controller(CONTROLLER.ONE, ['$scope', 'myFactory', 'CONTROLLER', function ($scope, myFactory, CONTROLLER) {
// use constant here
}]);
That being said you can only access the constant except from within the controller function itself. The names of controllers, services, factories etc must be accessible strings, which is not the case until the constant has been injected.
You could use a plain old JavaScript object outside angular to define the names.
var CONTROLLER = {
ONE: 'ControllerOne',
TWO: 'ControllerTwo'
});
I can only guess that you are trying to do this because the controller or directive you are writing will be referenced/used at multiple points throughout your html.

Why do angularjs controller declaration have this syntax structure?

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
});

AngularJS + Rails: Unknown provider: e

After moving to production server using Rails 4 and AngularJS, I came across error: [$injector:modulerr] Failed to instantiate module EcoApp due to:
Error: [$injector:unpr] Unknown provider: e.
After reading other stackoverflow questions and angular docs, I suppose the error appears because of minification. Unfortunately, I don't know angular good enough and after several attempts to fix my code, I decided to search for help here.
My controller file (in CoffeeScript):
angular.module('EcoApp')
.controller 'MyTripsCtrl', ($scope, $http) ->
$http.get('/mytrips.json').success((data, status, headers, config) ->
$scope.mytrips = data
return
).error (data, status, headers, config) ->
# log error
return
return
.controller 'NavbarIsActive', ($scope, $location) ->
$scope.isActive = (select_path) ->
select_path == $location.path()
return
.controller 'NavbarIsActive2', [
'$scope'
'$location'
($scope, $location) ->
$scope.isActive = (select_path) ->
select_path == $location.path()
return
]
As you can see, I tried to fix controller NavbarIsActive, which in my opinion is cause of trouble, but with no results. Any help would be much appreciated!
Yes, the problem is likely minification. If a minifier garbles your code into this:
.controller('Foobar', function (e) { .. })
then Angular doesn't have any information about what exactly it needs to inject. That's why the alternative injection syntax exists, which you need to use everywhere:
.controller 'Foobar', ['$scope', '$location', ($scope, $location) ->
..
]
You specify each dependency twice: once as a string, which will not get minified, and the second time as an arbitrary variable name in your actual function signature.

Angular JS Service not defined

I'm trying to create a universally accessible array in my application using services. I also implement ui-router in my appliaction.
I create the service in my app.js:
myFamilyApp.service('global', function() {
var eventArray = [];
return {
addEvent: function() {
eventArray.push(newObj);
}
}
});
then I call it from my controller:
myFamilyApp.controller('newEventController', [ '$scope', '$state',
function($scope, $state, global) {
eventConfig = {//variables to create event};
e = new Event(eventConfig);
global.addEvent(e);
});
but for some reason I'm getting this error:
TypeError: Cannot read property 'addEvent' of undefined
I know the issue is that the controller not recognizing the global variable, but I don't know why. I've looked at several other posts and generally messed around with it but I can't figure out why my controllers access the service. Any ideas?
I just realized my problem, and I apologize for posting this question I am still very new to angular. My issue was very simple, I wasn't passing in the 'global' when i created my controller
myFamilyApp.controller('newEventController', [ '$scope', '$state', 'global', function (params)

Angular Service Injection

I am working on a trivial task (that I got working) which adds an an .active class to dom elements in a tab nav. Simple. Got it working by following https://stackoverflow.com/a/12306136/2068709.
Reading over the answer provided and comparing their controller to example controllers on angular's website I came across something interesting that I don't quite understand.
On the AngularJS website, $scope and $location (and other services) are injected into the controller along with an anonymous function which defines the controller. But on the answer, the services are not injected, rather they are passed via the anonymous function. Why does this work? Shouldn't the service always be injected?
In terms of an example: Why does this
angular.module('controllers', [])
.controller('NavigationController', ['$scope', '$location', function($scope, $location) {
$scope.isActive = function(route) {
return route === $location.path();
};
}])
and this
angular.module('controllers', [])
.controller('NavigationController', function($scope, $location) {
$scope.isActive = function(route) {
return route === $location.path();
};
})
both work?
This may be trivial but its throwing my brain for a loop that I can't figure out.
The two examples are equivalent - they just make use of different syntax. The first example uses what they call "inline array annotation" (see here). The purpose of this alternate syntax is just to allow a convenient way to make the injected variable names different than the name of the dependency.
So for example, if you wanted the variable names to be "s" and "l", then you could write:
angular.module('controllers', [])
.controller('NavigationController', ['$scope', '$location', function(s, l) {
s.isActive = function(route) {
return route === l.path();
};
}]);
Actually they are injected in both cases, the difference between those two cases is in the first scenario you define and name the dependency this could be useful if you minify your js code and that way you are declaring explicitly the dependency for examply it could be:
angular.module('controllers', [])
.controller('NavigationController', ['$scope', '$location', function($s, $l) {
$s.isActive = function(route) {
return route === $l.path();
};
}])
that way angular will know which dependency to inject on which parameter without looking at the naming for each parameter.
the other case you need to be explicit and declare which dependency you'll inject by setting up the name.
I hope that helps.
This is how angular handles code minification. by keeping strings intact it can keep mapping vars when they are renamed.
if you take a look at the code of the controller https://github.com/angular/angular.js/blob/master/src/ng/controller.js#L48
you'll see that the constructor can accept both function and array.

Categories

Resources