Parent state is called twice when transition on child state - angularjs

app.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider.state('home', {
url: '/',
templateUrl: 'product/product.html',
controller: 'products'
}).state('productdetail', {
url: '/product/:productid',
templateUrl: 'product_details/productdetails.html',
resolve: {
Products: function($stateParams, Product) {
return Product.fetchList($stateParams.productid);
}
},
controller: 'productDetail'
}).state('category', {
url: '/category/:category_code',
templateUrl: 'category/category.html',
resolve: {
Categories: function($stateParams, Category) {
return Category.fetchList($stateParams.category_code);
}
},
controller: 'category'
}).state('category.product', {
// url: '/category/:category_code',
templateUrl: 'category/products.html',
// resolve: {
// Categories: function($stateParams, Category) {
// return Category.fetchList($stateParams.category_code);
// }
// },
// controller: 'category'
})
$urlRouterProvider.otherwise('/');
});
in my controller I use :
$state.transitionTo('category.product')
this will load my controller twice first it call http://localhost:3000/category/cat_code
then
http://localhost:3000/category

Related

Passing resolved data to child state in Ui-Router

So, I have a state where the resolve spits out an array which shows correctly on the frontend.
But I can't seem to be able to pass the parent resolve data to the child state.
$stateProvider.state('berliner', {
url: '/berlinerliste',
params : {search: 'Berliner 2017'},
resolve: {
fair: function(SearchService, $stateParams) {
return SearchService.getAllExhibitors($stateParams.search);
}
},
views: {
'header': {
templateUrl: 'header.htm'
},
'main':{
templateUrl: 'bl2017.htm',
controller: function($scope, fair){
$scope.fair = fair;
console.log($scope.fair);
}
}
}
})
.state('berliner.exhibitor', {
url: '/{id}',
resolve: {
exhibitor: function($stateParams, fair) {
var slug = $stateParams.id;
return slug;
}
},
views: {
'header': {
templateUrl: 'header.htm'
},
'wop':{
templateUrl: 'exhibitor.htm',
controller: function($scope, exhibitor, $filter){
$scope.fairs = $scope.fair;
console.log($scope.fair);
$scope.chosenexhibitor = $filter("filter")($scope.fairs, {'slug':exhibitor}, true);
console.log($scope.chosenexhibitor);
}
}
}
})
All the console log come out undefined.
What am I missing?
PLUNKR
Here's a Plunkr to examplify the issue.
I would say, that the concept should work.. just:
controller belongs to view. not to all views: {}
E.g. this (wrong)
// each view can have controller,
// but views : {} property 'controller' is not used at all
views: {
'header': {
templateUrl: 'header.htm'
},
'wop':{
templateUrl: 'exhibitor.htm',
},
controller: function($scope, exhibitor, $filter){
$scope.fairs = $scope.fair;
console.log($scope.fair);
$scope.chosenexhibitor = $filter("filter")($scope.fairs, {'slug':exhibitor}, true);
console.log($scope.chosenexhibitor);
}
should be adjusted as that:
views: {
'header': {
templateUrl: 'header.htm'
controller: function($scope, exhibitor, $filter){
$scope.fairs = $scope.fair;
console.log($scope.fair);
$scope.chosenexhibitor = $filter("filter")($scope.fairs, {'slug':exhibitor}, true);
console.log($scope.chosenexhibitor);
}
},
'wop':{
templateUrl: 'exhibitor.htm',
controller: ...
There is an example, how
parent does resolve
child view's controller consumes it
states:
.state('parent', {
url: "/parent",
templateUrl: 'tpl.html',
resolve: {
example: ['$timeout', function($timeout){
return $timeout(function(){
return {x: 1}
},100)
}],
},
})
.state('parent.child', {
url: "/child",
templateUrl: 'tpl.html',
controller: 'ChildCtrl',
})
child controller
.controller('ChildCtrl', ['$scope', 'example', function ($scope, example) {
console.log(JSON.stringify(example));
}])
Check it here

Could not resolve from state 'app'

I know that this has been asked before (here and here among others), but I just can't understand what is the problem with my code. Here it is:
(function () {
'use strict';
angular
.module('app.students', ['common', 'xeditable', "googlechart", 'iosDblclick', 'anguFixedHeaderTable', 'disableAll'])
.config(config);
/** #ngInject */
function config($stateProvider, $translatePartialLoaderProvider) {
// State
$stateProvider
.state('app.students', {
abstract: true,
url: '/students'
})
.state('app.students.studentList', {
url: '/',
views: {
'content#app': {
templateUrl: 'app/main/students/views/studentList/studentList.html',
controller: 'StudentListController as vm'
}
}
})
.state('app.studentsInProcess.studentList', {
url: '/process/:id',
views: {
'content#app': {
templateUrl: 'app/main/students/views/studentList/studentList.html',
controller: 'StudentListController as vm'
}
},
parent: 'app.students'
})
.state('app.students.studentDetails', {
url: '/:id',
views: {
'content#app': {
templateUrl: 'app/main/students/views/studentDetails/studentDetails.html',
controller: 'StudentDetailsController as vm'
}
}
});
// Translation
$translatePartialLoaderProvider.addPart('app/main/students');
}
})();
When I click on a link with a ui-sref of "app.studentsInProcess.studentList" i Get the error
"Error: Could not resolve 'app.studentsInProcess.studentList' from state 'app'"
What am I doing wrong? Please bear with me as this stuff is new to me.

$state.go seems not to be working in my Ionic project

So I have my login screen where I do a Facebook login (this works perfect) and upon success of FB login it should go to another view. I try to achieve this with
$state.go("app.start")
But its not working. It just stays on the login view. Not sure why my $state.go is not working ...
My controller for the login button:
angular.module('MovieBankUser.controllers', [])
.controller('LoginCtrl', function($scope, LoginService, $state) {
$scope.loggingIn = false;
$scope.login = function () {
if (!$scope.loggingIn) {
$scope.loggingIn = true;
LoginService.loginUser().then(function () {
$scope.loggingIn = false;
//$window.location.href = "#/app/start"
$state.go('app.start');
//console.log("TEST TEST");
});
}
}
});
Part of my app.js code for the routing:
// Routes
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'views/login/login.html',
controller: 'LoginCtrl'
})
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'components/sidebar_menu/menu.html',
controller: 'AppCtrl'
})
.state('app.start', {
url: '/start',
views: {
'menuContent': {
templateUrl: 'views/start/start.html',
controller: 'MovieCtrl'
}
}
})
.state('app.trending', {
url: '/trending',
views: {
'menuContent': {
templateUrl: 'views/trending/trending.html',
controller: 'MovieCtrl'
}
}
})
.state('app.trending-detail', {
url: '/trending/:id',
views: {
'menuContent': {
templateUrl: 'views/trending/trending_detail.html',
controller: 'MovieDetailCtrl',
resolve: {
movie: function($stateParams, MovieService) {
return MovieService.getMovieById($stateParams.id)
},
trailer: function($stateParams, MovieService) {
return MovieService.getTrailerById($stateParams.id)
},
cast: function($stateParams, MovieService) {
return MovieService.getCastCrewInfo($stateParams.id)
}
}
}
}
})
.state('app.outnow', {
url: '/outnow',
views: {
'menuContent': {
templateUrl: 'views/out_now/outnow.html',
controller: 'MovieCtrl'
}
}
})
.state('app.outnow-detail', {
url: '/outnow/:id',
views: {
'menuContent': {
templateUrl: 'views/out_now/outnow_detail.html',
controller: 'MovieDetailCtrl',
resolve: {
movie: function($stateParams, MovieService) {
return MovieService.getMovieById($stateParams.id)
},
trailer: function($stateParams, MovieService) {
return MovieService.getTrailerById($stateParams.id)
},
cast: function($stateParams, MovieService) {
return MovieService.getCastCrewInfo($stateParams.id)
}
}
}
}
})
.state('app.comingsoon', {
url: '/comingsoon',
views: {
'menuContent': {
templateUrl: 'views/coming_soon/comingsoon.html',
controller: 'MovieCtrl'
}
}
})
.state('app.comingsoon-detail', {
url: '/comingsoon/:id',
views: {
'menuContent': {
templateUrl: 'views/coming_soon/comingsoon_detail.html',
controller: 'MovieDetailCtrl',
resolve: {
movie: function($stateParams, MovieService) {
return MovieService.getMovieById($stateParams.id)
},
trailer: function($stateParams, MovieService) {
return MovieService.getTrailerById($stateParams.id)
},
cast: function($stateParams, MovieService) {
return MovieService.getCastCrewInfo($stateParams.id)
}
}
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/login');
});

Angular app initialization with asynchronous data

I need to initialize my Angular with some User data that the whole app depends on. Therefore I need the initialization to be resolved before the router kicks in and controllers are initialized.
Currently, I wrote the initialization code in a run() block of the angular module. The initialization involves an asynchronous http request to get user data and the rest of the application relies upon the user data.
How can I ensure that the http request is resolved before the router kicks-in initializing the controllers?
I am using the ui-router.
The initialization consists in the following:
1) get cookie 'userId'
2) get User from server (asynchronous http request, the whole app depends upon the User)
3) set authService.currentUser
this is a sample of the code
.run(['$cookies', 'userApiService', 'authService',
function($cookies, userApiService, authService){
var userId = $cookies.get('userId');
userId = parseCookieValue(userId);
userApiService.getOne(userId).then(function(user){
authService.currentUser = user;
});
}])
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$urlRouterProvider.when('/', '/main');
$stateProvider
.state('login', {
url: '/login',
views: {
'header': {
templateUrl: 'views/header.html',
controller: 'HeaderCtrl'
},
'content': {
templateUrl: 'views/login.html',
controller: 'LoginCtrl'
},
'footer': {
templateUrl: 'views/footer.html',
}
}
})
.state('main', {
url: '/main',
views: {
'content#': {
template: '',
controller: function($state, authService) {
if(!authService.isAuthenticated()) {
$state.go('login');
}
if(authService.isStudent()) {
$state.go('student');
}
if(authService.isAdmin()) {
$state.go('admin');
}
}
}
}
})
.state('student', {
url: '/student',
views: {
'header#': {
templateUrl: 'views/header.html',
controller: 'HeaderCtrl'
},
'content#': {
templateUrl: 'views/student.html',
controller: 'StudentCtrl'
},
'footer#': {
templateUrl: 'views/footer.html',
}
}
})
.state('admin', {
url: '/admin',
views: {
'header#': {
templateUrl: 'views/header.html',
controller: 'HeaderCtrl'
},
'content#': {
templateUrl: 'views/admin.html',
controller: 'AdminCtrl'
},
'footer#': {
templateUrl: 'views/footer.html',
}
}
})
}])
Expanding on someone's comment, you can create a root state that is a parent to all of your other app's states (children to the root). The root state resolves all the user data and then you can inject the user data to any controller or store it in a service.
$stateProvider
.state('root', {
url: '',
abstract: true,
template: '', // some template with header, content, footer ui-views
resolve: {
// fetch user data
}
})
.state('root.login', {
url: '/login',
views: {
'header': {
templateUrl: 'views/header.html',
controller: 'HeaderCtrl'
},
'content': {
templateUrl: 'views/login.html',
controller: 'LoginCtrl'
},
'footer': {
templateUrl: 'views/footer.html',
}
}
})
.state('root.main', {
url: '/main',
views: {
'content#': {
template: '',
controller: function($state, authService) {
if(!authService.isAuthenticated()) {
$state.go('login');
}
if(authService.isStudent()) {
$state.go('student');
}
if(authService.isAdmin()) {
$state.go('admin');
}
}
}
}
})
... // your other states
The key is that all of your app states must be a child of your root state i.e. root.<name> in your state declaration. This will ensure that no other controller starts until your user data is available. For more information on resolve and how to use it read here. Also, parent and child states.

state parameter value is mixed with url in UI-Router in angularjs when refresh is clicked

I am trying to creating web page to perform on edit actions in both in parent(first.edit) and child(second.edit) states.
I sending related state parameters through URL, those are captured by using regex patterns.
When I click on ui-sref="home.first.edit({firstId:10})" link the controller receiving state parameter firstId correctly i.e 10.
When I click on ui-sref="home.first.second.edit({firstId:10,secondId:20})" link or refresh the the state the controller receiving in correct value for firstId i.e 10/second/20.
and it is moving to parent state(home.first)
This is my js file
angular.module('MyApp', [
'ui.router'
])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
Here are the states:
$stateProvider.state('home', {
url: '',
views: {
'home_view': {
templateUrl: 'index.html',
controller: 'homeController'
}
}
})
.state('home.first', {
url: "/first",
params:{
firstId:null
},
views: {
'home_view': {
templateUrl: "first.html",
controller: 'firstCtrl'
}
}
})
.state('home.first.edit', {
url: "/{firstId:[0-9]+}/edit",
views: {
'first_view': {
templateUrl: "/edit_first.html",
controller: 'firstCtrl'
}
}
})
.state('home.first.second', {
url: "/second",
params:{
secondId:null
}
views: {
'first_view': {
templateUrl: "/second.html",
controller: 'secondCtrl'
}
}
})
.state('home.first.second.edit', {
url: "/{secondId:[0-9]+}/edit",
views: {
'second_view': {
templateUrl: "/views/testplan/projects/edit_second.html",
controller: 'secondCtrl'
}
}
})
Here is the rest of the code with controller definition
.controller(
'homeController',
function($scope, $state, $stateParams) {
// console.log($stateParams.firstId);
}
)
.controller(
'firstCtrl',
function($scope, $state, $stateParams) {
console.log($stateParams.firstId);
}
)
.controller(
'secondCtrl',
function($scope, $state, $stateParams) {
console.log($stateParams.secondId);
}
);
There is a working plunker
Your state definition could be simplified like this:
.state('home.first', {
url: "/first",
...
.state('home.first.edit', {
url: "/{firstId:[0-9]+}/edit",
...
.state('home.first.second', {
url: "/second",
...
.state('home.first.second.edit', {
url: "/{secondId:[0-9]+}/edit",
But the way you are expecting it to work should be like this:
.state('home.first', {
url: "/first/{firstId:[0-9]+}",
...
.state('home.first.edit', {
url: "/edit",
..
.state('home.first.second', {
url: "/second/{secondId:[0-9]+}",
...
.state('home.first.second.edit', {
url: "/edit",
These links will start to work then:
<a ui-sref="home.first({firstId:1})">
<a ui-sref="home.first({firstId:22})">
<a ui-sref="home.first.edit({firstId:333})">
<a ui-sref="home.first.edit({firstId:44444})">
<a ui-sref="home.first.second({firstId:4444})">
<a ui-sref="home.first.second.edit({firstId:1,secondId:333})">
<a ui-sref="home.first.second.edit({firstId:22,secondId:55555})">
Check it in action here

Resources