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.
Related
This question has been asked many times before and I've tried the answers but they do not seem to solve the problem I'm facing. I'm new to Angular and am trying to pass a value from the controller to a factory so that I can retrieve some JSON information through an API. While I'm able to get the value from my HTML to the controller, the next step is giving me a TypeError: Cannot read property 'getCityData' of undefined. My controller code is as follows:
app.controller('MainController', ['$scope', function($scope, HttpGetter) {
var successFunction = function(data) {
$scope.data = data;
}
var errorFunction = function(data) {
console.log("Something went wrong: " + data);
}
$scope.cityName = '';
$scope.getCityName = function(city) {
$scope.cityName = city;
HttpGetter.getCityData($scope.cityName, successFunction, errorFunction);
};
}]);
The factory code is as follows:
app.factory('HttpGetter', ['$http', function($http){
return {
getCityData: function(query, successFunction, errorFunction){
return $http.get('http://api.apixu.com/v1/current.json?key=MyAppKey&q=' + query).
success(successFunction).
error(errorFunction);
}
};
}]);
I've replaced my App key with the string "MyAppKey" just to be safe but my code contains the appropriate key. Also, it would be very helpful if I could get a bit of an insight on how the function invocations happen because there seem to be a lot of function callbacks happening.
Getting undefined could be because of the service not getting properly injected.
Try:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
Also as you said, to be on safer side you aren't using the right key, but anyone using your application can get the key by checking the network calls. So, ideally, one should make a call to the backend, and backend will send a call along with the secured key to the desired API endpoint and return the response data to front-end.
Can be due to ['$scope', function($scope, HttpGetter) ?
Should be ['$scope', 'HttpGetter', function($scope, HttpGetter) instead.
You used minified version and inject only $scope not HttpGetter but used as argument in controller function that's why got HttpGetter is undefiend and error shown Cannot read property 'getCityData' of undefined
So you should inject HttpGetter in your minified version ['$scope', 'HttpGetter'
use like:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
instead of
app.controller('MainController', ['$scope', function($scope, HttpGetter)
And if your MyAppKey is secured and want to hide from user then you should use it in server side
I'm quite new to Angular and I'm having issues with injecting $http into the following controller:
function(){
angular.module('nps-settings-support-tools', [])
.controller('SettingsSupportToolsController', [ '$scope', 'Settings', 'gettextCatalog', '$q', '$timeout',
'$rootScope', 'SweetAlert', 'CurrentUser', '$http',
function($scope, Settings, gettextCatalog, $q, UploadFile, $timeout, $rootScope, SweetAlert, CurrentUser, $http) {
var apiUrl = '/api/v1/';
I've read here that Angular cares greatly about the order of injections, but I've double-checked that the ordering is correct. Yet, when I'm running:
$scope.doTodo = function() {
return $http.get(apiUrl + 'support?tool=digest&type=todo');
};
I get the following errors in the console:
TypeError: Cannot read property 'get' of undefined
at Scope.$scope.doDetractors
So, thinking that my memory was incorrect, I also tried with:
return $http({url: apiUrl + 'support?tool=digest&type=responses', method: 'GET'});
Which obviously fails also because $http appears to be undefined, yet I can't see where I've gone wrong, as most SO questions / answers are about ordering of injections and accessing $http via an improperly ordered injection, which I'm not doing (as far as I can see).
Does anyone know what is going on, please?
You have parameter UploadFile in the controller function, but not in the array of strings.
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)
I am working with angular js at view layer. I need to use some global variable that will be used and modified by all the controllers method in my application:
var app = angular.module('myWebservice', ['ngCookies']).run(
function($rootScope) {
$rootScope.authToken = null; });
app.controller('UserController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.login= function() {
$http.defaults.headers.post = {'Accept' : 'application/json',
'Content-Type' : 'application/json'};
$http.post('/myServise/api/user/login-user', {
emailId : $scope.username,
password : $scope.password
}).success(function(data, status) {
if (status == 200) {
$rootScope.authToken = data.object.authToken;
}).error(function(data, status) {
console.debug(data);});
}// Else end
};// End Login
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.getRootScopeValues = function()
//$scope.getRootScopeValues = function($rootScope)
{
$scope.token = $rootScope.authToken;
console.log($scope.token);// Undefined
console.log($rootScope.authToken);// Undefined
}
});
I am new to Angular JS, I have also tried to use service but I don't know why I am not able to access global variable (authToken). Please help me I am stuck at this point ....Thanks in advance...
I am not sure how your application works but looks like you have a problem of asynchronous calls (while $http is working you are trying to access the variable which is not set yet). Please look at this answer about Asynchronous calls. Maybe this is your case? Also I should note that using $rootScope is always a bad idea. Try to avoid it. You should use service instead which is also a singleton object and always a much better and maintainable approach.
I need to use some global variable that will be used and modified by all the controllers method in my application
The best way to achieve this is using a Service, but you don't have to if you would like to leave it at the $rootScope
I have tried to use service as well but same results "Undefined"
Because the call for the authToken is asynchronous, the controller could run before the token returns from remote server.
You can add the token retrieval logic to the route definition as a 'resolve' field like this:
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/your/route', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
token: function() {
//return a promise with the token here
}
}
})
However, this is NOT good in your case as you will have to setup the 'resolve' for every route. If you are using AngularUI Route that supports nested routes, you can simply add the 'resolve' to the root state/route. This is what I've been using in my project.
If you are not using AngularUI Route, there's another way of doing it. You can assign the returned value of the $http.post to a variable in the $rootScope e.g. $rootScope.tokenPromise.
The returned of $http.post is a promise, you can use the 'then; method to register callbacks, and these callbacks will receive a single argument – an object representing the response.
In your controller, you will have put some extra lines, you will get the token asynchronously like this
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$rootScope.tokenPromise.then( function(token){
console.log(token); //depends on the returned data structure
} )
});
In your application 'run' block, you will have to create a promise at $rootScope.tokenPromise. you can either use $http to retrieve the token and get the promise there in the run block, or create a pending promise and retrieve the token elsewhere in other places, after which you can resolve the promise.
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});
...
}
]
);