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}
Related
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.
Pretty new to Angular, I am sure I'm missing something obvious here. I am using ui-router.
I want to provide a link to my clients so that they can click the URL link and visit the web app with the appropriate partial. I also want to be able to pass in parameters. Here's how I approached this (kind of hokey). This is in my main controller:
var pNumber = $location.search().number;
if (!(pNumber == null || pNumber == "")){
$state.go('view-ticket');
}
Here is my app.js:
$stateProvider
.state('home', {
url: "/",
templateUrl: 'partials/welcome-screen.html',
controller: 'mainPageController'
})
.state('submit-ticket', {
url: "/submit-ticket",
templateUrl: 'partials/ticket-submit.html',
controller: 'TicketSystemTestCtrl'
})
.state('view-ticket', {
url: "/view",
templateUrl: "partials/ticket-central.html",
controller: 'TicketCentralCtrl'
})
The logic is this: If the URL contains a param 'number' inject ticket-central.html partial.
However, when I run this in the debugger, it seems the first part of the code got executed before it loads the welcome-screen.html partial. How to solve this?
EDIT: I am trying to type this into the URL: http://localhost/techsupport/view and I want it to load the ticket-central.html partial into the main view. However, it won't work.
if i understand correctly all you want to do is to provide a possibility to 'deep-link' to the 'view-ticket' state.
for this search params are not the ideal solution as they are optional, just use path variables:
.state('view-ticket', {
url: '/view/:ticketNumber,
template: 'partials/ticket-central.html',
controler: 'TicketCentralCtrl'
})
also don't use the $location service if you don't really have to, have a look at $stateParams
here is a small plunkr with a welcome and a ticket state
launch the preview in a separate window to see how the url changes - you can also refresh on each page and the correct state will be loaded
https://plnkr.co/edit/r3UcYbfwET0OVwkd77Rv
'use strict';
angular.module('cbApp')
.config(function ($stateProvider) {
$stateProvider
.state('search', {
url: '/college/search',
templateUrl: 'app/collegesearch/views/collegesearch.html',
controller: 'collegeSearchCtrl'
})
.state('searchCollegeFilter', {
url: '/college/search/:streamId?cities&courses&branches&ordering',
templateUrl: 'app/collegesearch/views/collegesearch.html',
controller: 'collegeSearchCtrl'
});
});
Here my application calls the 1st state i.e 'search' with a url /college/search. Inside the controller I transition to another state searchCollegeFilter.
What I wanna do is navigate the user back to the back they came from when they click the browser back button. Say they came from '/' I want them to go back to home page. But in browser back history there are 2 entries for college/search. I want this to happen only for the 1st time.
For this northing is do with angularjs, the thing is you need to watch browser back event before navigating "window.onhashchange". By observing that you can make you check and can redirect default page
What I am doing in a different application would serve the purpose:
Basically: Specify parent states!
-> Then the logic is becoming easy.
You don't have to be specific about history or back button or anything like that.
Basically:
-> Check in
$rootScope.$on("$onstateChange", ...
-> If
the fromState.parent equals toState.parent
then $window.history.replaceState({}, "My Detail State Page", $state.url(toState)
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.
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"
})