I have a state route as follows :
.state("hospitals",
{
url: "/hospitals/:categoryName/:providerName",
templateUrl: "app/components/hospital/views/hospitals.html"
})
In general,hospitals pages have all the hospitals with all categories and all provider(hospital) group. In addition, from home page we can navigate to the hospitals page using the category or provider which will show hospitals based on category and provider group respectively. For these, I navigate using the following directives inside anchor tag.
ui-sref="hospitals({categoryName: category.KeyName})"
ui-sref="hospitals({providerName: provider.KeyName})"
So, this introduces a dirty slash when navigating with providerName.
hospitals//somehopitalNme
It is fine with category.
coupons/heart/
Once inside the hospitals page, I can search using category or providerName and get the list of hospitals. I was thinking of modifying the url in these searches(using ui-sref for the same page) since it makes sense to show the url matching to the search. I land in a trouble here. The search is a common search and can match either providerName or category or even a text as well. In this case, how can I navigate or how to use s-ref. I am fine with not using ui-sref and just going to the api or getting the data and updating the results which is easily achievable. However, I prefer the change of url since it shows what we are looking for.
So, now I understand that the state route which I provided is not suitable.
Please provide me an approach as to how to do it.
I was thinking of adding another state called "search" for this, which makes sense. But the templateUrl for this will be the same. Please suggest if I am in right direction or not.
Check this for detailed explanation and working example
Angular UI-Router more Optional Parameters in one State
we can use so called squash setting of the params : {} object:
.state("hospitals",
{
url: "/hospitals/:categoryName/:providerName",
templateUrl: "app/components/hospital/views/hospitals.html",
params: {
providerName: { squash: true },
categoryName: { squash: true },
},
})
Also check these:
Angular js - route-ui add default parmeter
Option url path UI-Router
Related
Is it possible to configure ui-router in an Angular 1.5 application to completely ignore the address bar?
Desired behaviour is something like this:
Navigating between states via UI does not change the URL
Changing the URL does not cause navigation between states, only UI or programmatic actions do (clicking the buttons, etc.)
Hitting F5 restarts the application from "default" controller
Original URL (especially query parameters) must still be accessible
UPDATE: I am creating an application with a very specific use case, not a website. Ordinary web browsing practices do not apply here. Please accept the requirements as they are, even if it may seem to contradict common sense.
Agreed that the stated approach is not good if we consider classic web app.
I tried to create a sample application with your requirement in mind.
Here is how my router configuration(router.config.js) file looks like in my fruits app:
.state('start', {
url: '/',
templateUrl: '../app/start/start.html',
controller: 'startCtrl as vm',
})
.state('fruits', {
templateUrl: '../app/fruits/fruitshtml',
controller: 'fruitsCtrl as vm',
})
.state('fruits.details', {
params: {
fruitId: undefined
},
templateUrl: '../app/fruits/fruitdetails.html',
controller: 'fruitDetailsCtrl as vm'
})
Explanation of States:
start:
url / is entry point of my application. If url is /, start state will be loaded.
fruits:
This state shows list of fruits in my app. Note that there is no url defined for this state. So, if we go to this state, url won't change (State will change, but url won't).
fruits.details:
This state should show detail of a fruit with id fruitId. Notice we have passed fruitId in params. params is used to pass parameters without using the url! So, passing of parameters is sorted. I can write ui-sref="fruit.details({ fruitId: my-fruit-id })" to navigate to fruit.details state and show details of my fruit with fruitId my-fruit-id.
As you might have already got it, the main idea is to use states as means of navigation.
Does my app pass your points?
Navigating between states via UI does not change the URL
Changing the URL does not cause navigation between states, only UI or programmatic actions do (clicking the buttons, etc.)
Hitting F5 restarts the application from "default" controller
Original URL (especially query parameters) must still be accessible
->
pass: as we haven't defined url for states
pass: changing url will change to state to start. The app will not take user to any different state, but it does changes state to start or we could say our default state.
pass: refresh will take you to start state
pass: if you write start in your url, you app will got start state.
Possible work around for the 2nd point, which is not passed completely: We can write code to check the url (in startCtrl controller) passed. If url contains extra things appended to /start, go to previous state. If url is 'start' continue loading start page.
Update:
As pointed by OP #Impworks, solution for 2nd point is also passed if we set url of our start state to /. This way, if we append any string to url, the state won't change.
I am facing a url structure problem using ui-router in AngularJS. I want to have first level SEO friendly url structure like this:
https://people-profile.com/mike-david-tringe
So I can grab the SEO name "mike-david-tringe" via stateParam and use it to find data in database and populate the page.
The $stateProvider has code like this:
$stateProvider
.state('people', {
url: '/:nameUrl',
templateUrl: 'app/frontend/page.tmpl.html',
params: {
nameUrl: {squash: true},
},
controller: "PageController",
controllerAs: 'vm'
})
.state('admin', {
url:'/admin/:userId',
templateUrl:'app/frontend/admin/admin.html',
controller:'AdminController',
controllerAs: 'admin'
})
With above code, I can have https://people-profile.com/mike-david-tringe working with nameUrl = mike-david-tringe and I got SEO friendly first level url link. mike-david-tringe is SEO friendly and most important keywords beside the domain name.
But with this structure, https://people-profile.com/admin/ or https://people-profile.com/login/ will not work now. Since my controller try to grab admin as nameUrl and looking for data. And admin is not a nameUrl so my database will return null, the app will fail.
In short, stateParam nameUrl will grab anything after "/" so the url setting will think admin and login is :nameUrl but in fact, it is not.
So how do I structure my app ui-router structure to have SEO friendly url like https://people-profile.com/mike-david-tringe but when url is https://people-profile.com/admin/, it will load admin.html template and use AdminController instead as I defined in $stateProvider?
All you need to do is swap the order of them. The router will check in order of definition, so if /:nameUrl comes before /admin it will trigger first. But if you put /:nameUrl last then it will trigger on any url that hasn't already triggered something above.
A word of warning however. Moving between two urls that trigger the same state (like two urls that both hit /:nameUrl in your case) will not reload the controllers on the page. Only changing state will do that. There are options to change this behaviour, but it has always been very buggy for me.
I have a state defined something like this:
$stateProvider.state("app.search", {
url: "/search?q",
templateUrl: "App/Search.html",
controller: "SearchController as vm",
});
When I want to navigate to the search page and specify a search term, I can do something like this:
$location.path("search").search({ q: "stuff" });
Which effective resolves to a url along the lines of #/search?q=stuff. If I then change the search term to "things", the search page correctly reactivates and searches as expected.
However, I'd like to be able to specify "random" querystring parameters which have not been defined in my url, and then have those parameters also reload the state. (Note: this is why I'm using $location.path instead of $state.go to change the URL). So for example, if I was searching for food, my URL may be:
#/search?q=stuff&type=food
And then I may be filtering on spice levels, which may change the URL to:
#/search?q=stuff&type=food&spice=medium
(etc).
The problem though, is that since I haven't defined all the other query string parameters (type and spice in this example), ui-router doesn't reload my page.
I can't use $state.go with { reload: true } because it ignores the unspecified parameters.
Is there a way I can trigger a page reload using "unspecified" querystring parameters? This post suggests I can make the route /search* but that doesn't appear to work for me.
I haven't found a nice way to do this yet with ui-router. If you're willing to sacrifice your integrity a little bit you could utilize an alternate format for your query params. You can use a single http url query param object and list all your criteria using a custom format.
e.g.
/search/q?stuff:type=food:spice=cinnamon
The route setup would look like:
$stateProvider.state("app.search", {
url: "/search?q",
templateUrl: "App/Search.html",
controller: "SearchController as vm",
});
and to navigate with the extra parameters:
$state.go('app.dashboard', { q: 'stuff:type=dessert:spice=cinnamon'});
to access the parameters on the route:
$state.params.q
You can then just parse out the 'stuff' value and then each name/value pair that was passed in.
PS> I'm not sure whether the colon (:) separator is valid but it was used to illustrate the proposed idea.
I write an application with angularjs and use ui router for dynamic routing , my app has a page for display list of news and when click on a news , Explanation of the news is showing
for example if I have a news with id=3 when i click on link of this news the url change to news/3 and when click on a news with id=5 url change to news/4 but i want to change url to news/subnews/third or news/subnews/fifth
my piece of code for change url and content is like this
.state('news', {
abstract:true ,
url: "/news",
templateUrl: "views/news/news.html",
})
.state('news.showAll', {
url: "",
templateUrl: "views/news/showAllNews.html",
})
.state( 'news.detail',{
url:"/:newsId",
templateUrl: "views/news/tmpShowDet.html",
controller:"newsShowing",
resolve:{
newsId: ['$stateParams', function($stateParams,newsId){
return $stateParams.newsId;
}]
}
})
what is the true way for display like news/subnews/....
How many 'subnews' do you want?
Translating numbers to words can get a little tricky, and spoken-language specific. Example: at 'subnews/101' do you want 'subnews/onehundredandone or subnews/onehundredandfirst or subnews/oneohone'.
I would recommend, if you only have a few subnews possibilities, going by categories.In that case, it seems you already know how to implement, or have access to the documentation for UrlRouteProvider.
If you have many subnews, I would leave the parameter as an integer, which is relatively spoken-language agnostic. You can always mask it or build a lookup table, etc if you don't want it displayed.
Speaking of which, if you still want to change the integer to a word, just use a lookup, and the url docs.
Cheers, bro
I'm working on a search app using AngularJs 1.0.8.
In order to allow bookmarking and sharing links I want to represent the current state of the search in the browser's location bar.
A URL might look like this
http://example.com/#!/search?s="Some query term"&page=2
So the app has to do two things:
update the URL when someone searches
Restore the state when another opens the same URL
What I currently do (maybe this is the wrong approach) is:
Configuring routeProvider to prevent the browsers from reloading on search param changes
...
$routeProvider.when('/search', {
templateUrl: 'app/search/view/List.html',
controller: 'listCtrl',
reloadOnSearch: false
});
...
Getting search results and setting location when someone presses the search button (searchArray holds the search parameters)
...
$location.search(searchArray);
...
Updating the search results accordingly.
...
$scope.search_results=data;
...
In order to restore the state I'm watching $location.search()
...
$scope.$watch(function () { return $location.search() }, function (newVal) {/* evaluate params and fire query */ });
...
My problem is, that location always changes twice. I've managed to overcome this issue by maintaining dirty flag.
As I think this maintaining state in URL is a popular scenario, I think there must be a better approach with Angular.
Could anyone guide me in to the right direction?