This one is baffling; I'm trying to use the simple $state.go() function in my app which uses ui-router, but I get this:
Uncaught Error: [$injector:modulerr] Failed to instantiate module MainApp due to:
Error: [$injector:modulerr] Failed to instantiate module GroupApp due to:
Error: [$injector:unpr] Unknown provider: $state
http://errors.angularjs.org/1.4.3/$injector/unpr?p0=%24state
at REGEX_STRING_REGEXP
Here is the code I am using:
var app = angular.module('GroupApp', ['ui.router']);
groupjs_config.$inject = ['$stateProvider', '$state', '$urlRouterProvider'];
app.config(groupjs_config);
groupjs_controller.$inject = ['$scope'];
app.controller('groupjs.ctrl', groupjs_controller);
//----------------------------------------------------
// FUNCTIONS
//----------------------------------------------------
function groupjs_config($stateProvider, $state, $urlRouterProvider){
// For any unmatched url, redirect to /state1
$stateProvider
.state('group', {
abstract: true,
url: "/group/:groupid",
onEnter: function(){
if (true){ //logged in
$state.go('group.home');
}
else {
$state.go('group.noaccess');
}
}
})
.state('group.home', {
url: "/group/:groupid",
templateUrl: "groups/group/group.html"
})
.state('group.noaccess', {
url: "/group/:groupid",
templateUrl: "groups/group/group_noaccess.html"
});
}
function groupjs_controller($scope){
$scope.hi = "hi";
$.material.checkbox('mycheckbox');
$scope.groups = [
];
}
Try injecting the $state to the onEnter method :
onEnter: ['$state',function($state){
if (true){ //logged in
$state.go('group.home');
}
else {
$state.go('group.noaccess');
}
}]
and take it out from the config:
groupjs_config.$inject = ['$stateProvider', '$urlRouterProvider'];
...
function groupjs_config($stateProvider, $urlRouterProvider){
Only providers and constants can be injected into config blocks see the table at the bottom of https://docs.angularjs.org/guide/providers
The $state can be injected into the controller, or any filter, factory, service, run block etc. but just not in config. In order for anything but a provider to be created it must first have been configured (this is what the config blocks are for, configuring providers of services/factories/values).
First change this line:
groupjs_config.$inject = ['$stateProvider', '$state', '$urlRouterProvider'];
to:
groupjs_config.$inject = ['$stateProvider', '$urlRouterProvider'];
Change your routing function like this:
function groupjs_config($stateProvider, $urlRouterProvider){
// For any unmatched url, redirect to /state1
$stateProvider
.state('group', {
abstract: true,
url: "/group/:groupid",
onEnter: ['$state',function($state){
if (true){ //logged in
$state.go('group.home');
}
else {
$state.go('group.noaccess');
}
}]
})
.state('group.home', {
url: "/group/:groupid",
templateUrl: "groups/group/group.html"
})
.state('group.noaccess', {
url: "/group/:groupid",
templateUrl: "groups/group/group_noaccess.html"
});
}
ui-router
$stateProvider
.state('admin', {
abstract: true,
url: '/admin',
template: '<div ui-view></div>'
})
.state('admin.index', {
url: '/index',
template: '<h3>Admin index</h3>'
})
.state('admin.users', {
url: '/users',
template: '<ul>...</ul>'
});
onEnter, onExit
Our app calls these callbacks when we transition into or out of a view. For both options, we can set a function we want called; these functions have access to the resolved data.
These callbacks give us the ability to trigger an action on a new view or before we head out to another state. It’s a good way to launch an “Are you sure?” modal view or request the user log in before they head into this state.
Related
I am trying to adapt to Angular's component (from code generated by Angular Fullstack Generator).
I tried to configure the routes to resolve "query" as per below:
angular.module('paizaApp')
.config(function($stateProvider) {
$stateProvider
.state('main', {
url: '/',
template: '<main query="$resolve.query"></main>',
resolve:{
query:function(){return null;}
},
.state('starred',{
url:'/users/:userId/starred',
template: '<main query="$resolve.query"></main>',
resolve:{
query:function($stateParams){
return {stars:$stateParams.userId};
}
}
})
.state('users',{
url:'/users/:userId',
template: '<main query="$resolve.query"></main>',
resolve:{
query:function($stateParams){
return {user:$stateParams.userId}
}
}
The following are the codes for the controller/component.
class MainController {
constructor($http, $scope, socket, Auth, query) {
this.$http = $http;
this.socket = socket;
this.awesomeThings = [];
$scope.isLoggedIn = Auth.isLoggedIn;
$scope.getCurrentUser = Auth.getCurrentUser;
$onInit() {
this.$http.get('/api/things',{params:{query:query}})
.then(response => {
this.awesomeThings = response.data;
this.socket.syncUpdates('thing', this.awesomeThings);
});
}////////
////////////////////////////////////// etc..
angular.module('paizaApp')
.component('main', {
templateUrl: 'app/main/main.html',
bindings:{query:'='},
controller: MainController
});
I am getting an error message - unknown query provider. However if I remove query from the constructor then the error message is "query is not defined".
Can you please see where I have gone wrong and whether I am supposed to inject the "query" variable into the controller? I am new to Angular 1, not to mention Angular 2.
Update: I have also tried something like this but didn't work:
angular.module('paizaApp')
.config(function($stateProvider) {
$stateProvider
.state('main', {
url: '/',
template: '<main></main>',
resolve:{
query:function(){return null;}
},
controller:function($scope,query){
$scope.query=query
}
And:
angular.module('paizaApp')
.component('main', {
templateUrl: 'app/main/main.html',
controller: MainController,
scope:{query:'='}
});
You shouldn't inject query on controller constructor. You could have do that if you have specified MyController as controller for state.
The query resolve is already passed in component bindings. You can directly get the value of query resolve inside this.query
I'm trying to go very simply to another state programatically and pass parameters, so:
$stateService.go('login', {
messages: [{
service: 'Auth',
type: 'error',
msg: "Your session has expired. Please log in to continue..."
}]
});
$stateService is to avoid circular dependancy between ui-router and state (both of which use $http)
var $stateService = $injector.get('$state');
This is the login state, as loaded into $stateProvider:
angular
.module('kitchenapp')
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'views/login/login.html',
controller: 'LoginCtrl',
controllerAs: 'vm'
});
}]);
When I go to the login controller, however
angular
.module('kitchenapp.controllers')
.controller('LoginCtrl', LoginCtrl);
LoginCtrl.$inject = ['$location', 'Auth', 'toastr', '$stateParams', '$log'];
function LoginCtrl($location, Auth, toastr, $stateParams, $log) {
var vm = this;
angular.extend(vm, {
name: 'LoginCtrl',
messages: $stateParams.messages,
...
$stateParams.messages is empty. What am I doing wrong?
Any parameter which should be part of state must be defined. Either in url or via params: {} object:
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'views/login/login.html',
controller: 'LoginCtrl',
controllerAs: 'vm',
params: { messages : null },
});
Check more details:
How to pass parameters using ui-sref in ui-router to controller
You should register "messages" parameter within the state. See https://github.com/angular-ui/ui-router/wiki/URL-Routing#important-stateparams-gotcha
This my main module definition:
$rootScope.$on('unauthorized', function () {
$state.go('login');
});
.config(
function ($stateProvider, $logProvider, $httpProvider) {
$logProvider.debugEnabled(true);
// main application area //
$stateProvider
.state('body', {
url: '/',
template: '<div ui-view />'
});
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'login.html',
controller: 'LoginController',
});
$httpProvider.interceptors.push('APIInterceptor');
});
Interceptor definition:
service('APIInterceptor', function($rootScope) {
// Just for testing
$rootScope.$broadcast('unauthorized');
}
It's not following this:
$state.go('login'); and seems like it's looping until Chrome fails the page. Without $state.go('login'); code runs ok but I need to open the login page on unauthorized. My question is how do I navigate to login state?
Thanks
Try this
$rootScope.$on('unauthorized', function ($state) {
$state.go('login');
});
My state configuration goes something like this:
.config(function ($stateProvider, $urlRouterProvider, $authProvider) {
$authProvider.facebook({
clientId: '16250xxxxxx',
scope: 'user_friends'
});
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('core', {
abstract: true,
template: '<ui-view>',
resolve: {
'authStatus' : function($auth, $q, User) {
var defer = $q.defer();
$auth.authenticate('facebook').then(function(result) {
User.update(result.data.user);
defer.resolve();
});
return defer.promise;
}
}
})
.state('home', {
parent: 'core',
url: '/home',
templateUrl: 'app/home/home.html'
})
....
.... other states
When my application loads, it enters the resolve block of 'core' state twice.
This causes the facebook authentication window to open twice..
Any clue why it would execute the core state twice ?
Found the reason for this occurence.
The satellizer $auth service would redirect to a default url upon resolving the authentication.
I simply had to reset that to '/home' in the config section of angular app
$authProvider.loginRedirect = '/home';
I'm using NodeJS+Express to serve an HTML page with an Angular app. It seems to work fine when it loads. There are no errors.
Problem is that that page is pretty much blank - except for the header. But the part that is supposed to go where <div ui-view></div> is, doesn't display anything.
Worse yet, when I go to an address, like
http://localhost:7070/admin/#/rounds
the browser just changes it to
http://localhost:7070/admin/#/
and goes back to displaying nothing.
My angular app, in index.js looks like this:
Some .run() and .config() settings
app.run(['$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
// It's very handy to add references to $state and $stateParams to the $rootScope
// so that you can access them from any scope within your applications.For example,
// <li ng-class="{ active: $state.includes('contacts.list') }"> will set the <li>
// to active whenever 'contacts.list' or one of its decendents is active.
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}
]);
app.config(["$locationProvider", function($locationProvider) {
//$locationProvider.html5Mode(true);
}]);
States definition:
app.config(
['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
console.log("Is this running at all?");
$urlRouterProvider.otherwise('/');
$stateProvider
.state("admin", {
abstract: true,
url: '/admin',
template: '<ui-view />'
})
.state("admin.login", {
url: '/login',
templateUrl: 'login.html',
controller: 'userLoginCtrl'
})
/* DASHBOARD */
.state("admin.dashboard", {
url: "",
controller: 'dashboardAppCtrl',
templateUrl: "dashboard.html"
})
.state("admin.subjects", {
url: "/subjects",
controller: 'subjectsCtrl',
templateUrl: "subjects.html"
})
/* ROUNDS */
.state("admin.rounds", {
url: "/rounds",
controller: 'roundsAppCtrl',
templateUrl: "rounds.html",
resolve: {
gameId: ['$stateParams', function($stateParams){
console.log("gameId ");
return $stateParams.gameId;
}]
}
})
.state("admin.round", {
url: "/round/:roundId",
controller: 'adminRoundCtrl',
templateUrl: "adminround.html",
resolve:{
gameId: ['$stateParams', function($stateParams){
return $stateParams.gameId;
}],
roundId: ['$stateParams', function($stateParams){
return $stateParams.roundId;
}]
},
});
}
]);
There is a working plunker
The answer is relatively simple
$urlRouterProvider.otherwise('/admin');
And instead of this
http://localhost:7070/admin/#/rounds
we have to try this
http://localhost:7070/admin/#/admin/rounds
The point is, every sub-state 'admin.xxx' is child state of the the 'admin' state. And that means, it inherits its url: '/admin'
Also, we used
//$locationProvider.html5Mode(true);
So, the startingurl would most likely be ...
EXTEND: as discussed in comments, IIS Express is used with virtual applicaton /admin, so this part will be in url twice /admin/#/admin...
http://localhost:7070/admin/index.html
// i.e.
http://localhost:7070/admin/
As a starting url of our app. Any routing is later managed after the # sign
http://localhost:7070/admin/#/admin/round/22
Check it here