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.
Related
I have 10 similar boxes in my dashboard each are showing different values for a specific device. When the user clicks on each, I have to direct them to new page which shows more information about that device.
the layout of the second page for all devices is the same. I just need to update the $scope.
What is a clean angular way to achieve this, preferably not adding query to the url?
I am using $stateProvider and tried to make it work with onEnter() but couldn't yet.
$stateParams should do the trick. To use it you need to specify the parameters when routing. For example:
(function(){
'use strict';
angular
.module('app')
.config(ApplicationConfig);
//set dependencies for ApplicationConfig
ApplicationConfig.$inject = ['$stateProvider'];
function ApplicationConfig($stateProvider){
//Define route states
$stateProvider
.state('main', {
abstract: true,
url: '/main',
templateUrl: 'pages/main/main.html',
controller: 'MainCtrl',
controllerAs: 'main',
cache: true,
params: {
user: null
}
});
}
Then you use $state.go('stateName', { param: param }), for example (following the previous example):
//Inside your original controller
function goToMainPage(param) {
$state.go('main', { user: param });
}
Finally, you access the parameter inside your destination controller by doing a $stateParams.param, or, in the previous example's case, $stateParams.user.
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.
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
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}
This is going to be difficult to explain but I'll try.
I am using UI-router in an angular app and would like t use the following URLS:
/contacts
/contacts/{id}
When you visit the /contacts page it will get a list of contacts from the server and display them. When you go to /contacts/1 it will get the contact 1 record from the server and show it.
My code currently looks like this:
.state('contacts', {
url: "/contacts",
templateUrl: "templates/contacts.tpl.html",
controller: "ContactsCtrl"
})
.state('contacts.contact', {
url: "/{contactID}",
templateUrl: "templates/contact.tpl.html",
controller: "ContactCtrl"
})
So far so good. but when you go to the second URL the parent is also activated so it's going to the server to get the list of contacts, even though they're not displayed, which is a waste.
I could set /contacts to "abstract:true" and use /contacts/list as the first URL, but that's not the URL I want to use and I do need to set a controller on the parent because I do have some logic I want to put in the parent (creating the navigation for that section).
Ideally, when the user hits /contacts I'd like the parent state to activate (to create the navigation) and run a default child state to list the contacts without redirecting to another URL. If the user goes to /contacts/8 then It would still activate the parent state but not the default state so it never goes to the server to get the contacts.
I hope that makes sense. I've not been able to create a plunkr, but the Angular UI guys kindly created one which shows the imperfect solution above.
http://plnkr.co/edit/gmtcE2?p=preview
I could set /contacts to "abstract:true"
That would be one part of the correct approach. A parent state should not load data that doesn't apply to a child, but your state tree doesn't have to reflect your URL structure exactly. For example:
.state('contacts', {
abstract: true,
url: "/contacts",
/* Various other settings common to both child states */
})
.state('contacts.list', {
url: "", // Note the empty URL
templateUrl: "templates/contacts.tpl.html",
controller: "ContactsCtrl"
})
.state('contacts.item', {
url: "/{id}",
templateUrl: "templates/contact.tpl.html",
controller: "ContactCtrl"
})