Append query parameter from controller -UI router - javascript

I have one parent state and child states for that parent. Parent state have one optional parameter reviewId. Everything is working good, when I am sending parameter in $state.go state is opened correctly. What I need is to append (add that optional query parametar in url) when creating new review (id is populated after making back end call).
This is url for opening existing review with id:
http://localhost:3000/#/planning?reviewId=1000.
When creating new review url is:
http://localhost:3000/#/planning. So what I need is after review is saved (Id is populated) to append ?reviewId=newId without state.go.
$stateProvider
.state('root.planning', {
url: '/planning?reviewId=',
abstract: true,
params: {
reviewId: null,
readOnlyMode: null,
locked: null,
editButton: null
},
reloadOnSearch:false,
views: {
'#': {
templateUrl: 'src/app/modules/planning/views/planning.tpl.html',
controller: 'PlanningMainController as reviewvm'
}
}
})
.state('root.planning.planning', {
url: '',
params: {
reviewId: null
},
data: {
planningChild: true,
stateTypeCd : "PLA"
},
reloadOnSearch:false,
templateUrl: 'src/app/modules/planning/views/tabs/tab.planning.view.html',
controller: 'PlanningController as planningvm'
})
EDIT
Tried also to update reviewId in stateParams after Id is accessed and then call $state.reload(). With this approach stateParams.reviewId is null after reload. And I was wondering if I can do this without reload.

$stateProvider
.state('root.planning', {
url: '/planning?reviewId',
abstract: true,
controller: function($scope, $stateParams) {
$scope.reviewId = $stateParams.reviewId;
}
call the function if $statePrams.reviewId is available. hope this will help you

Related

Angular UI-Router - Page refresh loses $stateParams

I've used $state.go to pass in an 'employee' object as a parameter to a page where the id is also used as a parameter in the url, but when the page is refreshed, all $stateParams are cleared from the state.
How can I prevent this from happening, and somehow store the data for the employee (as I said, employee id is used in url), so that when the page is refreshed, $stateParams is still populated with this employee's data based upon the id in the url?
State definition:
.state('employees/employeeDetails', {
url: '/employees/employeeDetails/:id',
templateUrl: 'views/employees/employeeDetails/employeeDetails.html',
params: {
employee: null,
id: null
},
controller: 'employeeDetailsMainController',
controllerAs: 'employeeDetailsMain',
resolve: {
lazyLoad: function($ocLazyLoad) {
return $ocLazyLoad.load('js/controllers/employees/employeeDetails/employeeDetailsMainController.js');
}
}
})
Directive with $state.go:
app.directive('viewEmployee', function() {
var directive = {
restrict: 'A',
scope: {
employee: '=',
state: '#state'
},
controller: function($scope, $state, $stateParams) {
$scope.goToEmployee = function() {
$state.go('employees/employeeDetails', { employee: $scope.employee, id: $scope.employee.id });
}
},
bindToController: {
employee: '='
},
link: function(scope, element, attrs) {
element.find('button').bind('click', function(index, employee) {
scope.goToEmployee();
})
}
}
return directive;
})
.state('employees/employeeDetails', {
url: '/employees/employeeDetails?employee&id',
templateUrl: 'views/employees/employeeDetails/employeeDetails.html',
controller: 'employeeDetailsMainController',
controllerAs: 'employeeDetailsMain',
resolve: {
lazyLoad: function($ocLazyLoad) {
return $ocLazyLoad.load('js/controllers/employees/employeeDetails/employeeDetailsMainController.js');
}
}
});
use querystring params li these it will retain them after refresh.
for more info check doc ui-router query params
you need to add in the route definition another item called :employee
url: '/employees/employeeDetails/:id/:employee'
But since employee is an object - so unless you wanna define each item as a param in the url or do a lookup based on the id when you get to the state of the employee itself from the backend... you have other options.
use a service to store the employee info
localStorage
UPDATE:
So based on what it seems the only genuine option should be to make a backend query to fetch the employee info based on the ID passed in the route. This is based on the fact that an end user could end up directly on the page and such means that there is a good chance the info will not be available in the service or the localstorage - you could check if its there and if not make a request (smart service).
You can use
$location.search($location.search('employeeDetails', { employee:
$scope.employee, id: $scope.employee.id });
and than get parameters that you need from $stateParams or if you use newest version $transation$ or on state on resolve
selectedFromUrl: ($location) => {
'ngInject';
return $location.search().employeeDetails;
},
If nothing help you can use cache

Get params from URL using $stateParams, UI-router. Undefined Value

I am passing a value from one state to another using UI-Router. In my controller when the url is updated I am trying to get access to the second parameter of my url using $stateParams, but for some reason I can get access to the first parameter but the second one is UNDEFINED. This is my code:
state 1, URL:
http://localhost:16009/#/5nqeAPqlv21/
state 2, URL:
http://localhost:16009/#/5nqeAPqlv21/details/PP163Ku3dOR
candidateContoller.js:
//go to state 2 (same controller for parent and child views)
$state.go('index.details', { "submissionIdd": publicSubmissionId });
//when located in the new state and new url:
console.log($stateParams.submissionIdd); //shows undefined
console.log($stateParams.token); //shows 5nqeAPqlv21
App.js:
$stateProvider
.state('index',
{
url: '/:token/',
views: {
'': {
templateUrl: 'AngularJS/Templates/indexView.html',
controller: 'candidateController as candCtrl'
},
'sectioncandidate#index': {
templateUrl: (_isNotMobile)
? 'AngularJS/Templates/candidatesView.html'
: 'AngularJS/Templates/candidatesMobileView.html'
}
}
})
.state('index.details', {
url: 'details/{submissionIdd}',
views: {
'sectioncandidate#index': {
templateUrl: (_isNotMobile)
? 'AngularJS/Templates/candidateView.html'
: 'AngularJS/Templates/candidateMobileView.html'
}
}
})
You do experience standard behavior of the UI-Router and Parent/Child state defintion:
parent state declares $stateParams (as url: '/:token/') - so there is just one declared - a token
child state gets all from parent(s), plus declares new parameter (as url: 'details/{submissionIdd}') - so it has both defined - token and submissionIdd,
So, while child has access to both params, parent state has just a token parameter
state 1 === PARENT, URL:
http://localhost:16009/#/5nqeAPqlv21/
here we will have submissionIdd undefined
state 2 === CHILD, URL:
http://localhost:16009/#/5nqeAPqlv21/details/PP163Ku3dOR
both are there submissionIdd=PP163Ku3dOR and token=5nqeAPqlv21
Extend - there is a working plunker
This states definition (in the plunker a bit adjusted)
.state('index',
{
url: '/:token/',
views: {
'': {
templateUrl: 'indexView.html',
controller: 'candidateController as candCtrl'
},
'sectioncandidate#index': {
templateUrl: 'parent.html'
}
}
})
.state('index.details', {
url: 'details/{submissionIdd}',
views: {
'sectioncandidate#index': {
templateUrl:'child.html',
}
})
will properly show state params for these links
href
<a href="#/5nqeAPqlv21/">
<a href="#/5nqeAPqlv21/details/PP163Ku3dOR">
<a href="#/5nqeAPqlv21/details/other">
ui-sref
<a ui-sref="index({token: '5nqeAPqlv21'})">
<a ui-sref="index.details({token: '5nqeAPqlv21', submissionIdd: 'another'})">
Check it here
You can prefer not to pass the the params in the URL unless there is an explicit requirement. I would prefer to use $stateParams in controller to fetch the data.
For this you need to define the default params in the state to
make it work.
$stateProvider .state('index.details', {
url: 'details',
params: {
submissionIdd: 'default',
},
views: {
'sectioncandidate#index': {
templateUrl: (_isNotMobile) ? 'AngularJS/Templates/candidateView.html' : 'AngularJS/Templates/candidateMobileView.html' ,
controller: function($stateParams){
console.log($stateParams.submissionIdd)
}
}
}
})

UI-router empty param causes navigation to wrong route

This should be simple but I just can't figure it out.
I have two routes:
$stateProvider
.state('users', {
url: '/users',
views: {'#': {
templateUrl: 'templates/users.tpl.html',
controller: 'UsersCtrl as users'
}}
})
.state('users.edit', {
url: '/{userId}',
views: {'#': {
templateUrl: 'templates/editUser.tpl.html',
controller: 'EditUserCtrl as editUser'
}}
});
This works fine if you use a ui-sref or $state.go to navigate to the "users" state by name, but if you type domain.com/users/ into the URL bar it goes to the edit state with empty userId parameter even though there is nothing after the trailing stash.
Normally this wouldn't be a problem but firing the editUser route with no userId causes console errors which would be a pain to fix.
Is this easily fixable?
Take a look to this post:
https://github.com/angular-ui/ui-router/issues/50
and this link referenced in the post:
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-make-a-trailing-slash-optional-for-all-routes
Your states definition should be
$stateProvider
.state('users', {
url: '/users',
views: {'#': {
templateUrl: 'templates/users.tpl.html',
controller: 'UsersCtrl as users'
}}
})
.state('users.edit', {
url: '/edit/{userId}',
views: {'#': {
templateUrl: 'templates/editUser.tpl.html',
controller: 'EditUserCtrl as editUser'
}}
});
your child state url should be '/edit/{userId}'. When we create a child state its url automatically added its parent state url. So if your url is '/{userId}' it will be 'domain.com/users/{userId}'. That's why for domain.com/users/ its navigate to the state users.edit with null parameter value.
https://github.com/angular-ui/ui-router/wiki/nested-states-%26-nested-views

Prevent reloading parent controller in ui-router

I have a problem with nested views in ui-router.
My layout is :
site.search
-----------------
site.search.runs
-----------------
site.search.runs.scheme
-----------------
site.search.runs.scheme.payment
-----------------
I don't want to change url that's why I use $state.go('', {}, {location:false});
I also use $stage.go('^'...) for back to parent.
But when I click on Back button on site.search.runs.scheme.payment or site.search.runs.scheme - site.runs controller also reloads (I don't use {reload:true}).
How to prevent reloading top level parent controller ?
I have found a problem like mine https://github.com/angular-ui/ui-router/issues/2096
Can anybody help me ?
My configuration is
$stateProvider
.state('site', {
abstract: true,
url: '',
template: '<ui-view/>'
})
.state('site.search', {
url: '',
parent: 'site',
controller: 'SearchController',
controllerAs: 'search',
templateUrl: 'js/search/search.tpl.html'
})
.state('site.search.runs', {
url: '',
parent: 'site.search',
params: {back: false, timestamp: 0, search: {}},
controller: 'RunsController as runsCtrl',
templateUrl: 'js/runs/runs.tpl.html'
})
.state('site.search.runs.scheme', {
url: '',
parent: 'site.search.runs',
params: {back: false, run: ''},
controller: 'SchemeController as schemeCtrl',
templateUrl: 'js/scheme/scheme.tpl.html'
})
.state('site.search.runs.scheme.payment', {
url: '',
parent: 'site.search.runs.scheme',
params: {back: false},
controller: 'PaymentController as payCtrl',
templateUrl: 'js/payment/liqpay/payment.tpl.html'
})
});
Back method calls this $state.go('^', {back: true}, {location: false, inherit: false});
A dirty trick you could do is wrap the controller code in an if statement and do something like this (this is by no means the best way, but it will certainly work):
// make sure you inject $state
// and put the if statement inside the main function of your controller
function RunsController($state) {
// var will return something like: site.search.runs.scheme
var currentState = $state.current.name;
if (currentState === 'site.search.runs') {
// in here put the code that would normally be in this controller for site.search.runs
}
}
Depends on when you are calling $state.go().
You could try the notify: false flag on the back method $state.go('^', {back: true}, {location: false, inherit: false, notify: false});
If youre trying to call state.go in the middle of a state already in transition, you should try $state.transitionTo() for example:
$rootScope.$on('$stateChangeStart', function(event, toState) {
$state.transitionTo('login');
}
I've found that transitionTo will not reload my parent controllers
$state.transitionTo('^', $stateParams, {
reload: false, inherit: false, notify: false
});
The parent property on the state is redundant if youre using dot notation so that could be causing a problem as only one is required. I would check $state.$current when youre calling 'back' to make sure you really are part of the parent's children.

Angular custom data to state objects

I'm following this sample on adding custom data to state objects but can't figure out what I'm doing wrong.
The idea is to have a Users state with a template that have 3 views: header, content and footer. The header-view gets updated with the child state's title and breadcrumb. The unnamed content-view will show the child's template (like a users list) and the footer will show summary data.
I have 2 issues:
My custom data object on my header's current state is undefined. ['Cannot read property 'title' of undefined]
If I exclude the custom data and just set the $scope values directly in the controller, it works fine but now get a 404 error. [GET http://localhost:3000/users 404 (Not Found)]. This makes no sense to me.
Am I on the right track with what I want to do? I'm unsure if I need the custom data or can I just set it in the controller?
angular.module('users').config(['$stateProvider',
function($stateProvider) {
// Users state routing
$stateProvider
.state('users', {
onEnter: function(){
console.log('state change to users');
},
abstract: true,
url: '/users',
views: {
'': {
templateUrl: 'modules/users/views/users.html'
},
'header#users': {
templateUrl: 'modules/core/views/page-header.html',
// data: { //<- this is undefined in the controller
// title: 'Users',
// breadcrumb: 'Home / Users'
// },
controller: function($scope, $state) {
$scope.title = 'Users'; //$state.current.data.title;
$scope.breadcrumb = 'Home / Users'; //$state.current.data.breadcrumb;
}
},
'footer#users': {
templateUrl: 'modules/core/views/page-footer.html'
}
}
})
.state('users.list', {
onEnter: function(){
console.log('state change to users.list');
},
url: '',
templateUrl: 'modules/users/views/users-list.html'
})
.state('signin', {
url: '/signin',
templateUrl: 'modules/users/views/authentication/signin.client.view.html'
});
}
]);
<section>
<div ui-view="header"></div>
<div ui-view=""></div>
<div ui-view="footer"></div>
</section>
You're receiving undefined because you're trying to access a data object belonging to the state itself, rather than the view you've defined it on. Typically, data would be defined against the state, but if you wish to do so against the view, you will need to use:
views: {
'header#users': {
data: {
title: 'Users',
},
controller: function($scope, $state) {
$scope.title = $state.current.views['header#users'].data.title;
}
}
}
As for your 404 error, there is nothing presented in the code that would cause this, so the problem must lay elsewhere.

Categories

Resources