UI-Router ui-sref to current state with new parameter - javascript

I have an app that has a location setting which when changed updates currency/ language etc.. This is visible on every page as it's in my parent state. When the location is changed using the below button...
<button ui-sref="{location: 'Europe'}">Europe</button>
//(which generate a href of 'href="#/Europe/home"' on my homepage)
the app should reload the current state and the suitable view and reinitialise the states controller using the new location parameters value.
The location setting button is in my parent state's view...
.state('root', {
abstract: true,
ncyBreadcrumb: {
skip: true
},
url: '/:location',
views: {
'#': {
templateUrl: function(params) {
return views + params.location + '/index.html';
},
controller: 'MainController as main'
}
},
params: {
location: null
}
})
My child states look like this...
.state('root.home', {
url: '/home',
templateUrl: function(params) {
return views + params.location + '/home.html';
}
}
This is working fine on the initial page that I load. The problem is if I load the app on the homepage(for example), navigate to another state and then change the location, the user is thrown back to the homepage(or whatever page the app was initially loaded on).
I think it's because as I navigate through the app the currentstate and generated href of the location buttons doesn't change to reflect the currentstate but I can't fix it. Is it an issue with how I'm referencing the current state in the ui-sref of the location button(not specifying a state and just updating the parameter in {})?
I could probably do $state.go in my controller through an ng-click but then I would be missing the generated href which we need for seo.
Any solutions would be greatly appreciated.

Related

Angular JS App persist state on browser refresh

I have angular Js App with nested views, the issue i am facing is when i click on F5 in nested view it gets redirected to default state, i want to persist the current state.
I can understand on reload it goes to parent ui-view to load the dependencies and after that it redirects to default view i have mapped but how can i redirect it to initial view instead of default view.
routes.js
$urlRouterProvider.otherwise('/dashboard');
.state('dashboard', {
url: '/dashboard',
},
views: {
// the main template will be placed here (relatively named)
'': {
templateUrl: 'views/dashboard.html',
controller: 'dashboardIndexController'
},
'headbar#dashboard': {
templateUrl: 'views/headbar.html',
controller: 'headbarController'
}
}
})
.state('dashboard.home', {
url: '/home',
templateUrl: 'views/dashboard.home.html',
controller: 'dashboardController',
})
.state('dashboard.campaigns', {
url: '/campaigns',
templateUrl: 'views/campaigns.html',
controller: 'showCampaign',
})
dashboard controller
$state.go('dashboard.home');
when i click refresh on campaigns state it redirects back to dashboard.home, which it should be as per code but how can i persist the campaigns or other nested states after reload.
Use window.localStorage.
Example
On successful landing on a page, store the current page name/url in the localStorage
window.localStorage.setItem('currentPage', window.location.pathname):
And after initialization, before redirecting to the home page, redirect to the previously stored url:
if (window.localStorage.getItem('currentPage')
$state.go(window.localStorage.getItem('currentPage'));
else
// go to home page normally

Child state with ui-router not resolved

I'm still working on an angular app, using the great ui-router. I'd like to use some dynamic nested states (I talked about it here), so I know it's possible.
Here is my code, with a specific state and its dynamic children states :
.state('home', {
url: '/home',
controller: 'RouteCtrl'
})
.state('home.state', {
url: '/home/:state',
controller: 'RouteCtrl'
})
$urlRouterProvider.otherwise('/home')
I have 3 buttons (more specifically, I use <a> to make it) to access 3 differents states : 'home', 'contact' and 'about'. 'contact' and 'about' are 'home' nested states and every state has a specific text to display when activated.
Unfortunatly, it appears that both of the children states aren't resolved from 'home' state.
Here is a plunker of the problem which match with my problem. Any idea ?
This will give you a working call to the new states:
$scope.redirect = function(state) {
console.log('redirect to state : ' + state);
if (state != 'home') {
$state.go('home.state', {
'state': state
});
} else {
$state.go('home');
}
}
However, it still won't change the text on the page, because the controller only sets it once when initially loaded.
Technically home, contact and about are not 3 states. What you appear to be doing is altering the content based of the parameters of the state. This could be achieved using one state and forcing ui-router to reload the state when you use $state.go
I have modified your plunkr here http://plnkr.co/edit/XXaltjG17FwY15tSbKaD?p=preview
Your state definition could look something like this,
.state('home', {
url: '/home?state',
controller: 'RouteCtrl'
})
The question mark makes the state parameter optional and also a query string.
The redirection could look something like this. You need to reload as you are going to the same route
$state.go('home', {state: state}, {reload: true});
Redirecting to the home page could look something like this. You need to disable inheritance for this redirect as you don't want to keep the query strings.
$state.go('home',{}, {reload: true, inherit: false});
The main problem here is that you want to have a variable in the state. You can't go to state home.about since it's not a given .state.
You should look at stateParams, or you can specify the URL where you want to go to the URL with Angular's $location.
Note: I think the url for a child state like home.state does not need the /home URL since it's in the father's state.

Can't navigate to ui-router state with URL

I'm working on a simple angular application using ui-router. I have a couple states for selecting and then editing information about a publisher. The relevant config:
.state('select-publisher', {
url: '/select-publisher',
templateUrl: '/Content/superadmin/src/templates/publishers/publishers.html'
})
.state('publisher', {
abstract: true,
url: 'publisher/{id:int}',
templateUrl: '/Content/superadmin/src/templates/publishers/publisher.html'
})
.state('publisher.details', {
url: '/details',
templateUrl: '/Content/superadmin/src/templates/publishers/details.html'
})
.state('publisher.ad-tags', {
url: '/ad-tags',
templateUrl: '/Content/superadmin/src/templates/publishers/ad-tags.html'
})
.state('publisher.native-ads', {
url: '/native-ads',
templateUrl: '/Content/superadmin/src/templates/publishers/native-ads.html'
})
Inside the select-publisher state I have a big list of available publishers. Each one of them is bound to an ng-click event that triggers the following function in my controller:
$scope.selectPublisher = function(publisher) {
publisherService.setSelectedPublisher(publisher);
$state.go('publisher.details', {id: publisher.Id});
};
This works just fine and takes me to the publisher.details state and renders the proper view. At this point the URL in my browser points to localhost:1337/superadmin#/publisher/39/details where 39 is the ID of the publisher that I selected.
The problem is, if I refresh this page or attempt to navigate directly to it by pasting the URL into the browser from another area of the application, I am ALWAYS taken back to the select-publisher state. I would like to be able to configure my states such that I am able to navigate to the details state (or any other state) based on URL.
Worth noting is that I do have a catch all route defined after all of my states:
$urlRouterProvider.otherwise('/select-publisher');
I'm assuming that for some reason this is being triggered but I can't reason as to why navigation works in my app using either $state.go as I have indicated in my controller as well as using ui-sref directive in my HTML templates but not through navigating directly to the URL.
Maybe it's because of missing slash url: /publisher/{id:int}

Retain parent state in AngularUI Router

I'm developing an application with AngularJS which has a phonebook. The state page.phonebook contains a list with users and companies and a form with filters. The data is loaded via ngResource from the backend. If I click on a user, I'm getting to the users detail page. When I now do a browser back (backspace), I'm getting back to the phonebook list, but with a new $scope. That means that I lost the old state with all my filters, data, etc.
I guess the problem is that I load the state page.phonebook.user in the page view, which replaces the page.phonebook state.
But is it somehow possible to retain the old state? This includes the scroll position, the filter values and the data from the server.
This is my state configuration:
$stateProvider
.state('page', {
abstract: true,
controller: 'PageController',
templateUrl: 'app/templates/page.html',
})
.state('page.phonebook', {
url: "^/phonebook",
templateUrl: 'app/templates/page.phonebook.html',
controller: 'PhonebookController'
})
.state('page.phonebook.user', {
url: "^/user/:userId",
views: {
'#page': {
controller: 'UserController',
templateUrl: 'app/templates/page.user.html'
}
}
});
You can very well maintain the state. You need to persist the filters, and scrolling position as part of your stateparams or a service. Once you are navigating between the pages you can retrieve that back.

AngularJS [UI-Router] urlRouteProvider.when() versus resolve for routing to child states

In my app I have a state called 'dashboard' with multiple child states
.state('dashboard', {
url: '/dashboard',
abstract: true,
// resolve async objects before controller instantiation.
resolve: {
productResolve: function ($state, authService, cacheService, productService) {
var cache = cacheService.getCache();
if (cache.length === 0){
return productService.getProductsAndCommoditiesAsync(authService.getCredentials().roleID)
.then(function(productData){
cacheService.setCache(productData);
},
function(errorMessage){
$state.go('error',{errorMessage:errorMessage});
});
}
}
},
templateUrl: '/static/app/partials/dashboard.html',
controller: 'dashboardCtrl',
})
// parent state: dashboard
.state('dashboard.splash', {
templateUrl: '/static/app/partials/dashboard.splash.html',
controller: 'dashboard.splashCtrl'
})
// parent state: dashboard
.state('dashboard.podSelector', {
// params array can be used instead of url to populate $stateParams
params: ['productIndex', 'commodityIndex'],
templateUrl: '/static/app/partials/dashboard.pod-selector.html',
controller: 'dashboard.podSelectorCtrl'
Which child state the user will be redirected to depends on his/her session cookie, and I was curious where the appropriate place was to do the redirecting.
One option I can think of are either to set the parent dashboard state to be not abstract so it is able to be navigated to, then check the session from within the dashboard parent resolve promise, and do a $state.go to a child depending on the result. I ideally would like to keep the dashboard parent state abstract as its useless on its own, but if it always will redirect to a child state then I guess its not important if it is.
The alternative I was thinking of is to handle it with a $urlRouterProvider.when(), something like:
$urlRouterProvider.when('/dashboard', function($state, sessionService){
if (sessionService.getSession() === undefined) {
$state.go('dashboard.splash');
}
});
This seems cleaner and a more logical place to put it, but say if I'm transitioning to the dashboard state from a login state, if I redirect in the resolve I can transition from the login page with a $state.go('dashboard') while if I use $urlRouterProvider I need to do a $location.path('/dashboard'), which I don't know how much transitioning to states with location paths versus $state.go is frowned upon.
Any advice would be appreciated.
Which child state the user will be redirected to depends on his/her session cookie, and I was curious where the appropriate place was to do the redirecting.
In general, if you want to drive navigation based on app state or session state, I would suggest you use a service to intercept the $stateChangeStart event and send them where they should be.
So, in your app's module.run callback, you could say:
$rootScope.$on('$stateChangeStart', function(event, toState) {
if (toState.name === 'dashboard') {
event.preventDefault();
switch (myCondition) {
case 1:
$state.go('dashboard.splash');
break;
case 2:
$state.go('dashboard.podSelector');
break;
default:
$state.go('somewhereElse');
break;
}
}
});
This way, you don't let the transition take costly time and energy by going to a state that you never intend to stay on, and you don't rely on $urlRouter.when.

Categories

Resources