UI router Unknown provider for injecting service into child state resolve - angularjs

Got Unknown provider when injecting service into the child state resolve function. But if defined a resolve in the parent state, it just works. Below there are some sample codes:
I defined a service module
angular.module('services', [])
.factory('myService', function() {
// my service here
})
and initialize the app
var app = angular.module('app', ['services', 'ui.router']);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider,
$urlRouterProvider) {
$stateProvider.state('wizard', {
url: '/wizard',
abstract: true
})
.state('wizard.step1', {
url: '/step1',
templateUrl: ... ,
resolve: {
name: function(myService) {
// do something with mySerice
}
},
controller: function(name) {
// controller codes here
}
})
}]);
I got the error Unknown provider complaining about myService in the wizard.step1 resolve. But if I add a random resolve in the parent state, like
$stateProvider.state('wizard', {
url: '/wizard',
abstract: true,
resolve: {
a: function() { return 1; }
}
})
then it works without error. Wonder what happens here?

In your controller you have to inject your service MyService, so define something like this
.state('wizard.step1', {
url: '/step1',
templateUrl: ... ,
resolve: {
name: ['myService', function(myService) {
// do something with mySerice
}]
},
controller: ['name', function(name) {
// controller codes here
}]
})

You have to inject your service in your config function :
var app = angular.module('app', ['services', 'ui.router']);
app.config(['$stateProvider', '$urlRouterProvider', 'myService',
function($stateProvider, $urlRouterProvider, myService) {
...
Another way is to embed your resolve code in a service and assign directly the service :
app.config(['$stateProvider', '$urlRouterProvider' ,'mySuperService',function($stateProvider,
$urlRouterProvider, mySuperService) {
...
resolve: {
name: mySuperService()
}
.constant('mySuperService', function() {
var serv= function(){
// your code
}
return serv;
}

Related

angularjs resolve is undefined

so in my state, i have
angular.module('app', ['ui.router', 'chart.js'])
.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/home',
component: 'home',
resolve: {
data: ['$http', function ($http) {
return $http.get('some api call')
.then(function (response) {
console.log("this is the response", response);
return response;
});
}]
}
});
}]);
then i get the proper response back. but when i check my resolve in here,
angular.module('app')
.component('home', {
templateUrl: 'Content/app/components/home.html',
bindings: {
resolve: '<'
},
controller: [
function () {
var vm = this;
vm.$onInit = function () {
console.log("this is the resolve", vm)
}
}]
});
i see that my resolve is undefined. Am i doing something wrong?
$stateProvider will bind what you specify inside the resolve object to your component, rather than binding the whole resolve object itself.
angular.module('app')
.component('home', {
templateUrl: 'Content/app/components/home.html',
bindings: {
data: '<'
},
controller: [
function () {
var vm = this;
vm.$onInit = function () {
console.log("this is the resolve", vm)
}
}]
});
Documentation link: https://ui-router.github.io/ng1/docs/latest/interfaces/state.statedeclaration.html#as-an-object

Angularjs custom headers with interceptors

I am trying to add a custom header using interceptors to every request I make on the app and I get the following error
Uncaught Error: [$injector:unpr] Unknown provider:
httpRequestInterceptorProvider <- httpRequestInterceptor <- $http <-
$templateFactory <- $view <- $state
// Ionic Starter App
(function () {
'use strict';
var app = angular
.module('app', ['ionic', 'auth0.lock', 'angular-jwt'])
.config(config)
.factory(factory)
factory.$inject = ['httpRequestInterceptor'];
config.$inject = ['$stateProvider', '$urlRouterProvider', 'lockProvider', 'jwtOptionsProvider', '$httpProvider'];
function factory(httpRequestInterceptor) {
return {
request: function (config) {
config.headers['X-switch-using'] = isApple;
return config;
}
}
}
function config($stateProvider, $urlRouterProvider, lockProvider, jwtOptionsProvider, $httpProvider) {
$stateProvider
// setup an abstract state for the tabs directive
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'components/menu/menu.html',
})
.state('app.home', {
url: '/home',
views: {
'menuContent': {
templateUrl: 'components/home/home.html'
}
}
})
.state('app.dashboard', {
url: '/dashboard',
views: {
'menuContent': {
templateUrl: 'components/template/template.html'
}
}
})
.state('app.signin', {
url: '/login',
views: {
'menuContent': {
templateUrl: 'components/login/login.html'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/home');
$httpProvider.interceptors.push('httpRequestInterceptor');
lockProvider.init({
clientID: AUTH0_CLIENT_ID,
domain: AUTH0_DOMAIN,
options: {
auth: {
redirect: false,
params: {
scope: 'openid',
device: 'Mobile device'
}
}
}
});
// Configuration for angular-jwt
jwtOptionsProvider.config({
tokenGetter: function () {
return localStorage.getItem('id_token');
},
whiteListedDomains: ['localhost'],
unauthenticatedRedirectPath: '/login'
});
}
})();
When I try to $httpProvider.interceptors.push('httpRequestInterceptor');
Any ideas? Cheers!
The problem is you are inject interceptor here factory.$inject = ['httpRequestInterceptor']; but what exactly the httpRequestInterceptor is ? you have not create anything with that name.
What you need to do is change below functions name to httpRequestInterceptor from factory:
function factory(httpRequestInterceptor)
and make it function httpRequestInterceptor()
Then replace .factory(factory) with .factory(httpRequestInterceptor) and you can remove factory.$inject if you dont need to inject anything else.
Problem 1
The first problem is that there is no dependency in your app like httpRequestInterceptor.
Problem 2
The 2nd major problem is that you can not inject a simple factory or service in the config phase of Angular.
From the docs
Only providers and constants can be injected into configuration
blocks. This is to prevent accidental instantiation of services before
they have been fully configured.
So consider changing your code like this:
// Ionic Starter App
(function () {
'use strict';
var app = angular
.module('app', ['ionic', 'auth0.lock', 'angular-jwt'])
.config(config)
//.factory(factory) // Removed factory
config.$inject = ['$stateProvider', '$urlRouterProvider', 'lockProvider', 'jwtOptionsProvider', '$httpProvider'];
function factory() {
return {
request: function (config) {
config.headers['X-switch-using'] = isApple;
return config;
}
}
}
function config($stateProvider, $urlRouterProvider, lockProvider, jwtOptionsProvider, $httpProvider) {
/** your state configuration here **/
$httpProvider.interceptors.push(factory);
/** your lockprovider and jwtOptionsProvider here **/
}
})();
I don't see a factory with httpRequestInterceptor which you are injecting in your factory named factory. If at all the factory httpRequestInterceptor is another module, you have inject that module as a dependency in your app module.
var app = angular
.module('app', ['ionic', 'auth0.lock', 'angular-jwt','inject
the module which has the httpRequestInterceptor factory'])
.config(config)
.factory(factory)

How to inject an external factory provider in angular config?

I'm trying to inject a factory provider from another js file but it can't locate the provider. If this can't be done, what is the better way?
demo.config.js
function configState($stateProvider, $urlRouterProvider, $compileProvider, demoProvider) {
// Optimize load start with remove binding information inside the DOM element
$compileProvider.debugInfoEnabled(true);
// Set default state
$urlRouterProvider.otherwise("/dashboard");
$stateProvider
// Dashboard - Main page
.state('dashboard', {
url: "/dashboard",
templateUrl: "views/dashboard.html",
data: {
pageTitle: 'Dashboard',
}
})
}
angular
.module('demoApp')
.config(configState)
.run(function($rootScope, $state) {
$rootScope.$state = $state;
});
demo.provider.js
(function () {
'use strict';
angular
.module('demoApp')
.provider('demo', function() {
return {
$get: function() {
return {
title: "Starcraft"
}
}
}
});
})();
I always put my own provider to controllers. Like in my directive
(function() {
'use strict';
angular.module('yourMod').directive('yourViewPage', yourViewPage);
angular.module('yourMod').controller('YourViewPageCtrl', YourViewPageCtrl);
function YourViewPageCtrl(YourProvider) {
//your code!!!
// Example YourProvider.getSomeThing();
console.log('My life for Aiur!!!');
}
})();

i am trying to test my angular controller using jasmine. But i am getting Error: [$injector:modulerr]

following is the code from my sample angular project.
app.js code:
(function () {
'use strict';
var app = angular.module('actorsDetails', [
// Angular modules
'ngResource',
// 3rd Party Modules
'ui.bootstrap',
'ui.router'
]);
app.config(['$stateProvider', '$urlRouterProvider', configRoutes]);
function configRoutes($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'app/home/home.html',
controller: 'HomeCtrl',
controllerAs: 'vm'
})
.state('form', {
url: '/form',
templateUrl: 'app/form/form.html',
controller: 'FormCtrl',
controllerAs: 'vm',
resolve: {
initialData: ['actorApi', function (actorApi) {
return actorApi.getActorsResource();
}]
}
})
.state('resource', {
url: '/resource',
templateUrl: 'app/resource/resource.html',
controller: 'ResourceCtrl',
controllerAs: 'vm',
resolve: {
initialData: ['actorApi', function (actorApi) {
return actorApi.getActorsResource();
}]
}
});
$urlRouterProvider.otherwise('/main');
}
app.run(['$state', function ($state) {
// Include $route to kick start the router.
}]);
})();
controller code:
(function () {
'use strict';
angular.module('actorsDetails').controller('HomeCtrl', HomeCtrl);
/* #ngInject */
function HomeCtrl($state) {
/* jshint validthis: true */
var vm = this;
vm.activate = activate;
vm.test = true;
vm.navigate = navigate;
activate();
function activate() {
}
function navigate() {
$state.go('form');
}
}
})();
**test.js**
describe('HomeCtrl', function() {
beforeEach(module('actorsDetails'));
beforeEach(inject(function ($rootScope, $controller) {
var scope = $rootScope.$new();
var HomeCtrl = $controller('HomeCtrl', {
$scope: scope
});
}));
it('should have a HomeCtrl controller', function() {
expect(true).toBeDefined();
});
});
there are the files I have included in my karma.config.js
I have added all the angularJS dependent files.
I have also added the controller file that i need to test
files: [
'src/lib/angular/angular.min.js',
'src/lib/angular-mocks/angular-mocks.js',
'src/lib/angular-resource/angular-resource.min.js',
'src/lib/angular-route/angular-route.min.js',
'src/app/app.js',
'src/app/home/home.controller.js',
'src/test/specs/*.js'
],
kindly pinpoint me, what is that I am doing wrong...
Mock out the $state object in your unit test.
var mockState = { go: function() {} };
var HomeCtrl = $controller('HomeCtrl', { $scope: scope, $state: mockState });
The $injector:modulerr is most likely related to your use of $state in your controller. Instead of mocking, you could try adding the library to your karma config, and loading the module in your unit test.
'src/lib/angular-ui-router/release/angular-ui-router.min.js'
beforeEach(module('ui.router'));

Error: [$injector:unpr] on tring to get resolve

I have a state with resolve:
function config($stateProvider, $urlRouterProvider) {
$stateProvider
.state('emails.list', {
url: "/list/:folder/:page",
parent: 'emails',
templateUrl: "views/emails.list.html",
data: { pageTitle: 'Mail Inbox' },
resolve: {
searchResult: ['Emails', function (Emails) {
return 1;
}]
}
});
}
And I have a controller for this state:
function EmailListCtrl($scope, searchResult, $stateParams, $state) {
...
}
angular.module('peachy').controller('EmailListCtrl', EmailListCtrl);
When I try to pass searchResult to controller I get an error [$injector:unpr]. How it can be fixed? (Or may be something wrong in configuration)
Angular version is 1.3.6
My mistake:
I called EmailListCtrl using ng-controller. Right way is setting controller name in state:
function config($stateProvider, $urlRouterProvider) {
$stateProvider
.state('emails.list', {
...
controller: 'EmailListCtrl'
});
}
There is a working plunker. Try to be sure that even EmailListCtrl recives all the needed dependencies properly:
function EmailListCtrl($scope, result, $stateParams, $state) {
$scope.data = { searchResult : result };
};
EmailListCtrl.$inject = ['$scope','searchResult','$stateParams','$state'];
the $inject contains clear definition for angluar IoC ... so I could even use result as param name instead of searchResult
Check it here

Resources