Closed iliakan closed 10 years ago
At the moment all state parameters are normalized to strings. This was the simplest approach to begin with, because any parameter that comes from the URL starts out as a string. It is also to ensure that in your example, navigating to '/model/123' behaves the same as transitionTo('model', { id: 123 }) and transitionTo('model', { id: '123' }).
I was thinking of extending this to allow arbitrary parameter types, but they would still be able to be converted to and from strings for URL handling.
I'm not sure I get your use case completely; it sounds like you're creating a new business entity of some type, and when you save it on the server you want to change the URL without changing the state? This is not something thats supported currently, and I'm not quite sure how it would work, you're expecting '/model/new' (or something like that) to map to the same state as '/model/123' and for $state to somehow know that even though 'new' and '123' are different that they represent the same parameter value? Presumably if you then navigated back from '123' to 'new' you'd actually want that to be treated as different though, so the user can create another new entity...
I think the easiest way to avoid the extra server roundtrip for reloading the object is to have a service that manages the remoting, and do some caching in there. When you save a new entity, you can prepopulate it into that cache.
Hi, I found the view change with transitionTo
quite troublesome, because it rerenders ui-view, and spoils current editing process (no way to avoid rerendering).
Actually, I'd like /model/new
to change to /model/123
on save without rerendering. Because the model has got the URL. But it seems there's no way to do so.
I'll leave this open to revisit later -- it's definitely not trivial to address.
One thing you could do is register '/model/new' with $urlRouter directly, and fetch a fresh object id from the server (without saving the object), and then redirect to '/model/(new-id)'.
Thank you very much for the project and for your answers.
Actually, what could work is reloadOnSearch: false
, but for URLs. You know, most of time we want to change state when params change. But sometimes we just need to update the url and keep current controller/view.
The stateUpdate
event (like routeUpdate
from Angular) can be propagatedto help.
The use case: mode/new -> model/:id
without reloading. Or any other case when valuable state is stored in the controller and there's totally no need to recreate it.
In this case, the controller mentioned in the state should know whether to go on with the state change and reloading OR it will handle the new URL on it's own. I guess, the neat & flexible solution would be to add parameter like: urlChangeHandler
which is a function, injected with the current controller. This function is called on path change and decides whether to reload or not. It also may ask the controller if needed.
What do you think about that? Do you feel like considering the patch?
P.S. I've found the other way around (change the URL and no state navigation at all). It seems, that works for me:
var off = $scope.$on('$stateChangeStart', function(e) {
e.preventDefault();
off();
});
$location.path('model/123').replace();
Would find very useful to have a way of changing the URL without the state change (expensive render, but want to keep URL up to date for user to be able to come back).
@iliakan can you elaborate on how that works exactly? I'd like to add it to the FAQ.
I was really curious, too -- it looked like an endlessly recursive listener at first glance.
However, the docs say $scope.$on "returns a deregistration function for this listener". So, since the listener calls the function that it returns, and that function deregisters the listener...
The listener deregisters itself the first time it is invoked -- hence it's a one-time prevention of routing when defined just-in-time before calling replace().
What jumps out at me at second glance is that $stateParams will probably still have the old values after this happens. So while the bookmarkability is achieved, any components relying on $stateParams might be misled unless they were manually updated by the app.
None of this is tested, but if you did:
//assuming $state is injected already
var off = $scope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams) {
evt.preventDefault();
$state.params = toParams;
angular.copy($state.params, $stateParams);
off();
});
$location.path('model/123').replace();
it might patch up the parameters.
Feels like hacking... I'm always up for that! ;) User beware though... this is way deep in stuff that isn't part of the API... so expect it to break down the road, if it even works now.
The 'dynamic parameters' feature should make this sort of thing unnecessary hopefully; you'll be able to change parameters marked as dynamic in $stateParams, and the location will update automatically, but no transition will happen.
For anyone using this, there is a small gotcha - say you are in state with url "question/1", then use this hack to go to "question" and then, without the hack, navigate back to "question/1" - this won't trigger a state change since that's the state your app is actually in the whole time.
Yes to be thorough you should probably deal with that, too. See https://github.com/angular-ui/ui-router/blob/master/src/state.js#L233
I used
var off = $scope.$on('$stateChangeStart', function(e) {
e.preventDefault();
});
off();
$location.path('product/123').replace();
Since product is an URL preassigned with a state. The app still render. Does anyone have run into this before and might have a solution?
Any news on "dynamic parameters" ?
@zerko There were some partial efforts made, but it'll be a little while before I can take them over and complete them.
The above hacks break with 2.7
@nateabele, @ksperling is there any specific issue for 'dynamic parameters' ("you'll be able to change parameters marked as dynamic in $stateParams, and the location will update automatically, but no transition will happen") to have ability to track it? This issue is closed. I've tried to search any other similar issue - found only "dynamic query params". But it seems that's other issue.
@ksperling This should be reopened, the hack was never ideal in the first place and this is a very useful behavior.
Something is in the works.
+10
@timkindberg anything that can be shared ? I would like to help as we need this !
This is the prerequisite: #454 -- that's as far as anyone's gotten so far.
+1 this is something that angular needs
+1 with example :
I have a product page where you can click on a product variant, like a color, to reload the images and such things. URL needs to change, but not the rest of the page since the only operation is product.applyVariant(v_id)
.
Interested in any immediate workaround
We use the following workaround:
$stateProvider.state('search', {
abstract: true,
templateUrl: '/partials/search/search.html'
});
$stateProvider.state('search.widget', {
url: '/search/{params:.*}'
});
And serialize/deserialize search parameters to/from params
Cons - http://local/search
url is impossible in that case, only http://local/search/
+1 I have a list of products (which are on one route), and clicking one of the products opens popup. I need to change URL for that popup, so that someone can send that URL to a friend (which will open same popup). But I have problems, making it to do it silently.
+1 @andreev-artem's workaround won't work for me as the URL is completely different from any of the others.
I have a modal that can be opened from any page, and it needs it's own URL. This is proving to be very difficult to do and is discouraging me from continuing to use AngularJS
+1
About https://github.com/angular-ui/ui-router/issues/64#issuecomment-19181158 On the current master (with optional url parameters) changing urls within the same states still reload the states.
Example: /a/b/:c/:d reloads the associated controller when moving from /a/b/c to /a/b/c/d.
@Gahen I'm not sure what you mean here. Optional parameters and dynamic parameters are not the same thing.
Oh! You are right, sorry for the confusion. I see now that they are still a future feature.
@nateabele Does this mean we can update the URL to anything without changing to reloading the state?
@joshhunt Yes. There are now multiple ways to manipulate URLs and states independently. Dynamic parameters (linked above) are one. Here's another: https://github.com/angular-ui/ui-router/blob/master/src/urlRouter.js#L199-L250
Awesome, deferIntercept
seems ideal - I hacked my work around to roughly the same way by ensuring i could bind to $locationChangeSuccess before ui-router (after seeing defaultPrevented
in the update code) - Being able to do this the "official" way is obviously preferrable.
<3 ui-router
Is there an addition to the docs that explains how to use the newly added features?
@Maidomax Yep, it's all in the API docs, which you can view by cloning the repo, then running grunt ngdocs
.
@nateabele Thanks for the info. Looks cool. I ran into a problem, tho. The new deferIntercept()
function exists in the src
folder, but when I included it into my project with bower, after some errors, I realized that it does not exist in angular-ui-router.js
(or the minified version) in the release
folder.
Did you forget to add the new version to the release folder, or it is not yet done?
[O]r it is not yet done?
@Maidomax Correct. It will be available in 0.3.
Can you provide a code snippet on how to use it? It is still not clear for me
@nateabele How can I use version of ui-router with this file: https://github.com/angular-ui/ui-router/blob/master/src/urlRouter.js#L199-L250 ?
Tried this in my bower.json:
"angular-ui-router": "git://github.com/angular-ui/ui-router.git"
But there is no deferIntercept()
anyway.
Is there any timeframe for the 0.3 release?
I'm very keen to use this feature as well. I've tried using the {dynamic:true} method however I just get the following error in the console:
Invalid params in state 'myState'
Is this feature available in the current release? Will there be any more documentation on how to use this? I've looked in the official API and guide for this feature however wasn't able to find anything.
but this currently work `$state.go('symbol', {symbolId:data.id}, {notify:false});``
does it match the requirements?
@daohodac Your exact solution hasn't quite worked for me in that it was still reloading the controller. It did however introduce me to $state.go and lead me to the solution I was looking for.
In order to have my URL updated with search parameters, I used the following $state.go function , where 'params' was a basic object with the URL parameter name and values.
$state.go('SearchResults.params', params, {location:"replace", inherit:false} );
This was used alongside two states, one of which is required to be abstract in order for the controller not to be reloaded.
$stateProvider .state('SearchResults', { abstract: true, url: "/search-results", templateUrl: "searchResults.html", controller: 'searchResultsController' }) .state('SearchResults.params', { url: "?param1¶m2¶m3" })
@jjaburke91 How I can recieve $stateParam with this function? $stateParam is empty
@pokep17 I've been using $state.params to access the parameters.
@nateabele what is the timeline for the dynamic-params
branch getting merged into master
?
@vladtar Pretty soon. Probably within the next few weeks.
Great. Looking forward to it.
+1
A coveted feature, indeed. +1
Here's the use case to prove my point.
I'm editing a Model. On save I want to change URL to
/model/:id
(id
comes form server), but calling$state.transitionTo('model', {id: ...})
causes the state change and hence the model is RELOADED. As if it were not on client!I'm trying to pass the existing model to the state, so that may keep it (by reusing in resolve):
state.transitionTo('model', {model: modelObject})
. But the normalization code stringifies the "model", so that's not an object any more.Is what I'm doing conceptually wrong? Is there any really good reason to keep normalization which prevents it from working?