Force ui-router to reload on querystring changes - angularjs

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.

Related

Dynamic parameters with ui-router

I'm developing a search app with angular using ui-router.
Requirements:
The search form has too many fields and all have to be optional.
Users should share with another users the URL that display the page with the result list. (So I need to use querystring)
So I could have urls like
path/to/url/list?p=123&v=876
path/to/url/list?c=yes&a=true&p=123
path/to/url/list?z=yes&c=yes&a=true&p=123
path/to/url/list?z=yes&v=876&a=true&p=123
And endless combinations. I know that I can use $location.search() to get all params in json format. That is great! but the question is How can I define the url state with ui-router? Define explicitly all params in the url is not an option. I have read many post but I didn't find a concrete answers.
If you're getting parameters from $location you don't need to define them in state explicitly.
I think, the best way is to use 'resolve' property of $stateProvider configuration:
$stateProvider.state('mystate', {
// Some code here
resolve: {
queryData: ['$location', ($location) => {
$location.absUrl(); // Contains your full URI
return true;
}]
}
});
It's kind of initialization. After that, ui-router will cut URI, but you will store needed data. This case also works fine, when user passing URI directly in browser address input.
Also you can try to set $urlRouterProvider with $urlMatcher for this purposes, but it will be more difficult.

Multiple optional route parameters and pretty urls with Angular ui router

I am trying to use multiple optional parameters to make urls looks like
/:region/:direction/:subdirection/page/
where all params instead of the last one are optional.
I've tried to use
params:{region: {value: 'default', squash:true}, ...}
for each optional parameter, but when some of them are missed in url, the router doesn't work.
So, the only solution I've found in order to save pretty urls in this situation is to declare multiple routes:
.state('page', {
url: '/:region/page'
}
.state('page-direction', {
url: '/:region/:direction/page'
}
.state('page-subdirection', {
url: '/:region/:direction/:subdirection/page'
}
Additionally:
1. there will be no subdirection without direction,
2. region will be in every link, but it is variable
Are there any optional solutions?
Thnx!
The default parameters are for internal routing, example
$state.go('page-subdirection');
The above will redirect to the state and the $stateParams.region will be the default value you defined for that state.
While $state.go('page-subdirection', {region: 'newValue'); will make $stateParams.region to be newValue in that specific case.
The same apply for constructing the URL from the view:
<a ui-sref="page-subdirection">
<a ui-sref="page-subdirection({region: 'newValue'})">
It may also depend on what your final goal is. From what you're describing, it seems that you may actually be trying to pass in filters into a single state, not necessarily trying to route to 3 different states.
If in the case of filtering a single state, I'd recommend using query parameters as described in the docs (https://github.com/angular-ui/ui-router/wiki/URL-Routing). The advantage is that query parameters are not required or used from a routing point of view, they're simply parameters that your controller will utilize to filter data or tweak the view.
Snippet from above doc link:
Query Parameters
You can also specify parameters as query parameters, following a '?':
url: "/contacts?myParam"
// will match to url of "/contacts?myParam=value"
If you need to have more than one, separate them with an '&':
url: "/contacts?myParam1&myParam2"
// will match to url of "/contacts?myParam1=value1&myParam2=wowcool"

AngularJS: get url path without routeParams

Take this route for exmaple
when('/coordinator/editApplications/:appId', {
templateUrl: 'assets/app/templates/coordinator/editApplications.tpl.html',
module: "/coordinator",
})
Without using regular expressions, is there a property/method available in Angular that will allow me to get the path value with the parameters stripped off?
The value I would want for this example would be /coordinator/editApplications
This needs to be be universal because there could be multiple params or differently named params. I can't find anyway on the $route or $location to get this value as they all seem to contain the params.
Again, I know i can use regExp to do this but I want to avoid that. I also don't want to just add another property to the route w/ the non-param url value.

Angular UI Router with multiple optional parameters

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

Multiple optional parameters in Angular.js

I typically use querystrings for filtering results, eg:
URL: /Events/List?type=art&city=miami&life=present
I can put them in any order and get the same results, eg:
URL: /Events/List?city=miami&life=present&type=art
URL: /Events/List?life=present&type=art&city=miami
I can also make them optional, eg:
URL: /Events/List?type=art,
or: /Events/List?type=art&life=&city=
Question: How can I achieve this same "effect" with Angular.js routes? given the fact that parameters are passed all in a "RESTful" way in Angular
I was thinking in something like this:
URL: /Events/List/city/miami/life/present/type/art
Which I can achieve with a route like this:
.when('/Events/List/city/:city?/life/:life?/type/:type?', { ... }
But I already see many problems:
Order of parameters is important (I would have to define many times the route?)
Optional parameters will give a non intuitive URL,
eg: /Events/List/city/life/type/art,
and this is not the case in optional querystrings (they are more intuitive to read I think): eg: /Events/List/?city=&life=&type=art
If you want to use query strings angular has $location.search() that is both a setter and getter.
The difference between angular search and window version location.search is the query falls after the url hash and when setting or getting it uses objects rather than strings
See Using $location in developer's guide
You can inject $routeParams into your controller. Here's an example from the docs:
// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
http://docs.angularjs.org/api/ngRoute.$routeParams
I recently encountered a similar need (the ability to grab an unknown quantity of arguments off the path), and had started off by looking at $routeProvider. I ultimately abandoned that effort in favor of ui.router.
The most powerful (but possibly also tedious) approach for you would be to work with regex parameters. Consider the following (a snippet from some code I'm currently authoring):
$stateProvider
.state("list", {
url: "/",
controller: "PluginsListController",
templateUrl: "PluginsList.html"
})
.state("path", {
url: "/{plugin}/*path",
controller: "PluginDetailsController",
templateUrl: "PluginDetails.html"
})
;
The second state accepts two positional parameters: a plugin and a path. The path argument is a wildcard, that grabs everything after the immediately preceding slash. The idea here is that I can specify something like http://www.myfirsturl.com/app/MyFirstPlugin/level1/level2/level2.php, and end up with "MyFirstPlugin" in $stateParams["plugin"] and "level1/level2/level2.php" in $stateParams["path"]. It's up to the application logic to handle the long path parameter (and you would be likewise responsible for consuming this variable-length argument), but this approach does allow you to write a single state handler for an unknown number of url paths.

Resources