Angular $routeProvider resolve creates injector exceptions - angularjs

I've set up an controller with a corresponding resolve function
window.ResolveCtrl = ['$scope', 'resolvedData',
function ($scope, resolvedData) {
console.log("RESOLVED:", resolvedData);
}
];
window.ResolveCtrlResolve = {
resolvedData: ['Api', '$q', function(Api, $q) {
var defer = $q.defer();
Api.someApiCall(function (err, data) {
if (err) defer.reject(err);
else defer.resolve(data);
});
return defer.promise;
}]
};
Here is the $routeProvider
$routeProvider.when('/example', {
templateUrl: "partials/example.html",
controller: 'ResolveCtrl',
resolve: ResolveCtrlResolve
});
The first console.log correctly logs the resolvedData object with it's contents, however it is directly followed by an $injector error:
Error: [$injector:unpr] Unknown provider: resolvedDataProvider <- resolvedData
Why is this happening?
UPDATE: Seems the controller constructor is called 2 times in a row, but I don't know why.

Related

AngularJS - problems when using resolve

I basically need to call a server that's will return me a JSON structure before load the controller.
I was using many methods to archive that, but it's not working. It's don't show me any error and the page got blank. Any clue about what's going on ?
This is my controller..
angular
.module('app',[
'ngAnimate',
'ui.router',
'ui.bootstrap',
'ngCookies'
])
.run(function($rootScope) {
$rootScope.backendServer = "http://localhost:5000/";
})
.config(['$urlRouterProvider','$stateProvider', function($urlRouterProvider,$stateProvider) {
$stateProvider
.state('cms',{
url: '/my',
templateUrl: './app/templates/my.html',
controller : 'my',
resolve: {
dbState: function ($q) {
var defer = $q.defer();
Database.check().then(function (s) {
defer.resolve(s);
});
return defer.promise;
}
}
})
}])
.controller(function ($scope){
})
...and this is my service:
angular
.module('app')
.factory('Database',['$http', '$rootScope','$q', function($http, $rootScope, $q) {
return {
check: function () {
var call = $rootScope.backendServer + 'cms/database/check';
return $http.get(call);
}
}
}]);
don't create a defer object when you already returning a promise. so remove the defer and just return the factory function
also, inject the Database service to resolve
resolve: {
dbState: function(Database) {
return Database.check()
}
}
In the controller catch it like this
.controller("ctrl", function($scope, dbState) {
console.log(dbState.data)
})
Demo

Resolving resource using ui-router

I face such problem: I have abstract state:
$stateProvider.state('bookings.clients', {
url:"/clients",
abstract:true,
views:{
"#":{
templateUrl:"/Static/CrmPages/CrmMainPage.html",
controller:"CrmMainPageController",
}
},
resolve: {
clientsData:function(clientsDataService) {
return clientsDataService.loadData('ihor.korotenko#n-cube.co.uk');
},
clientsGroupsData: function (userGroupsService) {
//return "some";
return userGroupsService.api.query(function (data) {
userGroupsService.data = data;
}).$promise;
}
}
});
As you can see there are two resolve objects.
Than, I inject this objects to controller in child state:
angular.module("crmModule")
.controller("mainPageController", ['clientsGroupsData', 'clientsData', "$scope", "$rootScope", "$translate", 'clients', 'cultureProvider', '$state', function (clientsGroupsData, clientsData, $scope, $rootScope, $translate, clients, cultureProvider, $state)
My resource provider:
angular.module("crmModule")
.service("userGroupsService", ['$resource', function ($resource) {
var self = this;
self.data = [];
return {
api: $resource("/api/groupsapi/getallgroups"),
data: self.data
}
}])
Child state:
$stateProvider.state('bookings.clients.overview', {
url:"/overview",
views:{
"crm.main":{
templateUrl: "/Static/CrmPages/main-page.html",
controller:"mainPageController"
}
},
});
The problem is following: when controller instantiates I see that injected object is not empty and resolved(It`s ok), but after that I get an exception
Error: [$injector:unpr] Unknown provider: clientsGroupsDataProvider <- clientsGroupsData <- mainPageController
How can I fix this?
So I found the reason of this error, it occurs because I attach controller in html via ng-controller directive, and of course, ui-router can`t inject dependency because it doesnt intantiate controller.

UI-Router will not resolve $http call

I have a api that i want to resolve name for "bubble". This i would like to inject into controller - but problem is that i have tried different approaches and all just say...undefined and some injection problems... :(
Code:
.state('bubbles', {
abstract: false,
url: "/bubbles/:bubbleId/feed",
controller: 'BubblesController',
data: {
authorizedRoles: [USER_ROLES.editor]
},
resolve: {
resolvedBubbleName: function ($http, $stateParams) {
var url = 'https://XXXXXXX.net/api/Bubble/11111111-1111-1111-1111-111111111111';
return $http.get(url)
.then(function (response) {
console.log('response ' + response);
return response;
});
},
views: {
'navigation': {
templateUrl: "/raqt/shared/partials/navigation.html"
},
'main': {
templateUrl: "/raqt/bubbles/partials/bubbles.html"
//controller: function ($scope, resolvedBubbleName) {
// $scope.resolvedBubbleName = resolvedBubbleName;
// // resolvedBubbleName is always undefined, i.e.,
// // UI router is not injecting it
//}
}
},
}
})
In my controller i tried different approaches and this that i think should work... gives error injection...
BubblesController.$inject = ['$stateParams', '$state', '$log', '$timeout', '$interval', '$scope', 'BubblesService', 'CONFIG', '$http', 'resolvedBubbleName'];
function BubblesController($stateParams, $state, $log, $timeout, $interval, $scope, BubblesService, CONFIG, $http, resolvedBubbleName) {
$scope.title = 'bubbles-controller';
alert(resolvedBubbleName);
$scope.bubbleId = $state.params.bubbleId;
Error from page
Error: [$injector:unpr] Unknown provider: resolvedBubbleNameProvider <- resolvedBubbleName <- BubblesController
http://errors.angularjs.org/1.3.15/$injector/unpr?p0=resolvedBubbleNameProvider%20%3C-%20resolvedBubbleName%20%3C-%20BubblesController
at REGEX_STRING_REGEXP (http://localhost:3604/js/lib/angular/angular.js:63:12)
at http://localhost:3604/js/lib/angular/angular.js:4015:19
at Object.getService [as get] (http://localhost:3604/js/lib/angular/angular.js:4162:39)
at http://localhost:3604/js/lib/angular/angular.js:4020:45
at getService (http://localhost:3604/js/lib/angular/angular.js:4162:39)
at Object.invoke (http://localhost:3604/js/lib/angular/angular.js:4194:13)
at $get.extend.instance (http://localhost:3604/js/lib/angular/angular.js:8493:21)
at http://localhost:3604/js/lib/angular/angular.js:7739:13
at forEach (http://localhost:3604/js/lib/angular/angular.js:331:20)
at nodeLinkFn (http://localhost:3604/js/lib/angular/angular.js:7738:11) <div ui-view="main" class="ng-scope">
I can see that $http call is having data and i know controller works well otherwise - but this resolve driving me mad.. :(
I will be off for couple of hours - but i WILL ge back to this if you see some problems in my code i will ge back and answer!... :)
I would say, that you've wrongly nested views : {} into the resolve : {}. There is a working plunker
I just moved your definitions into correct positions and it is working
.state('bubbles', {
abstract: false,
url: "/bubbles/:bubbleId/feed",
//controller: 'BubblesController',
data: {
authorizedRoles: [{}], //USER_ROLES.editor]
},
resolve: {
resolvedBubbleName: ['$http', '$stateParams',
function($http, $stateParams) {
//var url = 'https://XXXXXXX.net/api/Bubble/11111111-1111-1...';
var url = 'someData.json'
return $http.get(url)
.then(function(response) {
console.log('response ' + response);
return response.data;
});
}
],
},
views: {
'navigation': {
templateUrl: "raqt/shared/partials/navigation.html",
controller: 'BubblesController',
},
'main': {
templateUrl: "raqt/bubbles/partials/bubbles.html",
controller: ['$scope', 'resolvedBubbleName',
function($scope, resolvedBubbleName) {
$scope.resolvedBubbleName = resolvedBubbleName;
}
]
}
},
})
Also, one very important note:
controller belongs to view - not to state
You can read more here:
Are there different ways of declaring the controller associated with an Angular UI Router state
Check the working example here
EXTEND
In case, that we adjusted all the code as above and we are provided with this error:
Error: [$injector:unpr] Unknown provider: resolvedBubbleNameProvider <- resolvedBubbleName <- BubblesController
We are most likely in one of these scenarios:
we have elsewhere in our state hierarchy reused the "BubblesController", while not having resolve : { 'resolvedBubbleName': ... } in place
we declared somewhere ng-controller="BubblesController" - which is not managed by UI-Router. And it does not have access to so called locals (containing resolved values)
so, be sure where is the controller defined - all will start working then...

Loading controller on demand using AngularJS and RequireJS

I'm using Angular UI-router and trying to download/load controller when the routing changes. I used resolve and category, the data.data returns the js file content as string. I'm not sure to make the controller available to angular. Please help
My module.js contains below routing code
state("privacy", {
url: "/privacy",
controllerProvider: function ($stateParams) {
return "PrivacyController";
},
resolve: {
category: ['$http', '$stateParams', function ($http, $stateParams) {
return $http.get("js/privacy.js").then(function (data) {
return data.data;
});
} ]
},
templateUrl: localPath + "templates/privacy.html"
})
The below controller exist in "js/privacy.js"
socialinviter.controller("PrivacyController", function ($scope) {
$scope.me = "Hellow world";
});
I also tried with require js but I'm getting error "http://errors.angularjs.org/1.2.16/ng/areq?p0=PrivacyController&p1=not%20aNaNunction%2C%20got%20undefined"
resolve: {
deps: function ($q, $rootScope) {
var deferred = $q.defer(),
dependencies = ["js/privacy"];
require(dependencies, function () {
$rootScope.$apply(function () {
deferred.resolve();
});
deferred.resolve()
})
return deferred.promise;
}
}
I have resolved the issue and I thought the solution would be helpful for others
Step 1: On your config, include the parameter $controllerProvider
mytestapp.config(function ($stateProvider, $controllerProvider)
Step 2: telling angular to register the downloaded controller as controller, add the below inside the config
mytestapp.config(function ($stateProvider, $controllerProvider) {
mytestapp._controller = mytestapp.controller
mytestapp.controller = function (name, constructor){
$controllerProvider.register(name, constructor);
return (this);
}
......
Step 3: Add the resolve method as below
state("privacy", {
url: "/privacy",
controller: "PrivacyController",
resolve: {
deps : function ($q, $rootScope) {
var deferred = $q.defer();
require(["js/privacy"], function (tt) {
$rootScope.$apply(function () {
deferred.resolve();
});
deferred.resolve()
});
return deferred.promise;
}
},
templateUrl: "templates/privacy.html"
})

angularjs app structure/ $scope

I can't seem to wire this up properly. I'll list the appropriate pieces. My issue is accessing the injected resources. All of the dependent pieces are undefined when I try to reference them.
var app = angular.module('app', ['ngResource','ui.bootstrap', 'ngGrid','app.services', 'app.directives', 'app.controllers'
])
.config(['$routeProvider', function ($routeProvider) {
return $routeProvider.
when('/', { templateUrl: 'partials/transaction.view.html', controller: 'TransactionCtrl' }).
when('/about', { templateUrl: 'partials/about.view.html', controller: 'AboutCtrl' }).
when('/transaction', { templateUrl: 'partials/transaction.view.html', controller: 'TransactionCtrl' }).
otherwise({ redirectTo: '/' });
}])
.config(['$httpProvider', function ($httpProvider) {
return $httpProvider.responseInterceptors.push(['logger', '$rootScope', '$q',
function (logger, $rootScope, $q) {
var error, success;
success = function (response) {
$rootScope.$broadcast("success:" + response.status, response);
logger.log("success:" + response.status);
return response;
};
error = function (response) {
var deferred;
deferred = $q.defer();
$rootScope.$broadcast("error:" + response.status, response);
logger.log("error:" + response.status);
return $q.reject(response);
};
return function (promise) {
return promise.then(success, error);
};
}
]);
}])
.run(['$rootScope', 'logger', function ($rootScope, logger) {
return $rootScope.$on('$routeChangeSuccess', function (event, currentRoute, priorRoute) {
return $rootScope.$broadcast("" + currentRoute.controller + "$routeChangeSuccess", currentRoute, priorRoute);
});
}]);
...the controllers are here:
angular.module('pennyWatch.controllers', ['$scope', '$location','logger', 'ngGrid', 'transactionService']).
controller('TransactionCtrl', [function ($scope, logger, ngGrid, transactionService) {
//code here
}]).
controller('AboutCtrl',[function ($scope, logger) {
$scope.logEntries = logger.logEntries;
}]);
So none of the resources I specified are available (all undefined): '$scope', '$location','logger', 'ngGrid', 'transactionService'
Any light shed on this would be greatly appreciated!
Thanks
I'm pretty sure the syntax for a controller is:
.controller('TransactionCtrl', ['$scope', 'logger', 'ngGrid', 'transactionService', function ($scope, logger, ngGrid, transactionService) {
//code here
}]);
You first list what to inject, then as the last element of the array to define a function with parameters that will represent what's injected.
For instance you could even have:
.controller('TransactionCtrl', ['$scope', 'logger', 'ngGrid', 'transactionService', function ($s, logr, ngGrid, transServ) {
//code here
}]);
This is to allow for easy minification.
The alternative controller syntax uses the parameter names when choosing what to inject. And since minification usually involves shortening variable names, it's suggested you use the syntax above.
Alternative syntax:
.controller('TransactionCtrl', function ($scope, logger, ngGrid, transactionService) {
//code here
});
I think you are swapping module-loading with service-injection
when declaring the pennywatch.controllers module, you should invoke the angular.module function passing the module dependencies in brackets, not the services. many of the services you cannot access are in the ng module, for instance
service injection is applied at the controller level

Resources