Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibility to not reload state when state parameter is changed #100

Closed
stasgrom opened this issue Apr 24, 2013 · 20 comments
Closed

Possibility to not reload state when state parameter is changed #100

stasgrom opened this issue Apr 24, 2013 · 20 comments

Comments

@stasgrom
Copy link

Hi,

currently our URLs look like:

/requirements/:id/details/comments

When id changes, several views are reloaded (specifically the details and the comments related ones). We would like a possibility to get a notification on the change of a parameter without actually reloading the state. The problem with reloading the details and comments states right now is that the views are re-generated and one could see the flickering on the screen, while in fact the only thing we want to change is the data inside the view.

I understand that currently the ui-router doesn't support reloadOnSearch=false or a similar concept, which could help me here if I decided to move the id parameter to the search part of the URL. Is this option planned to be supported? Are there any suggestions of how to handle the problem right now?

Thanks.

@stasgrom
Copy link
Author

I checked and saw that if I use a search URL parameter that isn't modeled in any state then changing this parameter in the URL doesn't reload any state. This is of course good, since I can actually listen to the changes on $location and perform my own logic. The problem however is that once I transfer to another state using the $state.transitionTo() API (for example from ../comments to ../attachments) I'm losing this parameter in the URL, since ui-router lets through only parameters that are known to the new state.

@jssebastian
Copy link

I am also looking for the ability to not reload on URL changes, although in my case I am changing the path rather than the query parameters. This is actually the reason I started looking at ui-router instead of angular's $routeProvider, because $routeProvider's reloadOnSearch option does not prevent reloading when the path part of the url changes.

I have several use cases for it. One is the familiar master/details pattern similar to what @stasgrom mentioned. That is, when transitioning from:

/user/33/events

to

/user/33/events/245

the parts of the page that are not related to the individual event number 245 should not need to reload.

Another is that even for widgets that need to be updated on the URL change, I would prefer to manually call an update method that preserves some UI state. This is for UI state that is not reflected in the URL, such as what type of graph to use to display some data, which columns of a table to show, etc. I could refactor this state out of the controller but I think that is not the cleanest architecture (I have multiple instances of the same widget on a page, so I would need to look up the state of the correct instance on reload).

@ksperling
Copy link
Contributor

I'm wondering if another interesting approach to preserving some UI state would be to give the (new) controller access to the scope of the previous controller for the same view in cases where they are 'compatible', so you could copy across that data.

(per-parameter reload=false support is still on the TODO list though)

@laurelnaiad
Copy link

Great work on the router. I mean it. I realize I'm appearing out of nowhere but this issue just gave me the heebeejeebies.

I just left the Ember camp for Angular (at least in theory) and was feeling awesome about it -- studied up, had some good architectural thoughts about how to accomplish my goals... and it never occurred to me that parent views would be reloaded when they're still in the URL hierarchy... It's after 1 am and now I'm not going to be able to sleep!!!

Just kidding (sort of). That'll teach me to read GitHub issues and study this late at night. So if the path "/user/33/events/245" has nested ui-views for "user" and "user/:userId" and "user/:userId/events" and "user/:userId/events/:eventId" then transitioning to event ID 246 is going to rerender all of those templates? Uhoh. If the user template is long and scrolls vertically on the left side of the page (just for example) and the user has scrolled to the bottom, then it will be rerendered and "unscrolled" (i.e. scrolled to the top) due to transitioning to a different event? And all of that code is rerun? AJAX calls re-called?

You guys are scaring me! So much of the Angular API -- and ui-router -- fits my needs... I hope I'm misunderstanding.

@jeme
Copy link
Contributor

jeme commented May 2, 2013

@jssebastian I might actually have something covering that, basically it's a feature called sticky views, this cause the view not to reload if the sticky matches (unless it is a child of another view that is reloaded).

Instead if it's sticky, it will call a refresh method on the scope if defined, otherwise it will raise a $refresh event on the scope.

That is a feature of the views and not the state though, but I think it can cover it though.

I don't know it it makes sense for the ui-router though, as it has quite a different internal structure, and it also depends on weather or not @ksperling think it would be a fit.

@laurelnaiad
Copy link

@jeme you may have saved my night. I'm going to take a look at your project with fresh eyes tomorrow. Cheers! I really don't want to go back to Ember.

@jeme
Copy link
Contributor

jeme commented May 2, 2013

@stu-salsbury Keep in mind that both ui-router and angular-routing are in pre-release phases as opposed to Ember which is stable.

So in that way, they may still present a greater set of challenges or bugs. But feedback and contributions are more than welcome.

@jssebastian
Copy link

@jeme thanks for the pointer: I actually have not looked at angular-routing yet, I'll give it a look

@laurelnaiad
Copy link

Thanks @jeme. I'm totally fine with the earlier phases. More chance to
contribute!

I do need to settle on something that supports views/controllers/models
where parents don't reload when their children are swapped out -- that's
just a requirement for what I'm building (it requires a very deep and
featureful automagically-generated navigation UI). Somehow I got pretty
far into Angular before realizing it didn't have that kind of nesting
support by default (too much architecture and design in my head is the
obvious culprit -- I was busy designing my navigation service while grocery
shopping).

There are a number of reasons why I'd prefer to stick with Angular, so for
now my plan is to figure out how to do that, even if it means getting my
hands dirty on the way. I look forward to making it work with ui-router or
angular-routing or whatever ends up being a good fit. Both projects are
exciting.

@jssebastian
Copy link

@ksperling:

I'm wondering if another interesting approach to preserving some UI state would be to give the (new) controller access to the scope of the previous controller for the same view in cases where they are 'compatible', so you could copy across that data.

I wonder how you would know which scope in the old view maps to which scope in the new view... with ng-repeats and ui-ifs, this could get complicated. Not sure if there is a general solution.

My app is built as a tree of widgets, so perhaps the best way to keep state is to not burden the routing with this task but use a service to preserve this state outside the scope, with some application-specific logic to find the state for a widget given an identifier or a position in the tree or something.

(per-parameter reload=false support is still on the TODO list though)

I think there are certainly cases where it could be useful. There are situations where I know how to update the view to react to an event, and the only reason I want to update the URL is so it is a working deep-link for the user. For instance if a user changes graph type, I have an animated transition between the two types. I don't want the entire page and graph to reload, but I would like to record the graph type in the URL. Also I don't want to lose the user's scroll position.

Perhaps a mechanism to tell ui-router to ignore a specific url update completely could do the trick, though it may not be the cleanest design choice.

@laurelnaiad
Copy link

I think there are certainly cases where it could be useful. There are situations where I know how to update the view to react to an event, and the only reason I want to update the URL is so it is a working deep-link for the user. For instance if a user changes graph type, I have an animated transition between the two types. I don't want the entire page and graph to reload, but I would like to record the graph type in the URL. Also I don't want to lose the user's scroll position.

That pretty much says what I meant. Having reviewed the original issue of this thread, I realize that this talk of "keeping the M, V and C intact in parent states/routes" thing is turning into hijacking, so I'll stop.

I'm green on Angular, but it seems like the idea of passing scope to the subsequent controller with something that signals "you're new to this page and here's the pre-existing scope, take it or leave it" would be a good start for the issue of preserving model data during transitions -- especially if the new controller has enough context to know what to do with the previous scope (i.e. how to interpret it) -- who gave this to me? Or as U.S. Vice Presidential Candidate Admiral John Stockdale famously said in his debate, seemingly in senility, "Who am I? Why am I here?" So if the controller function in the state got parameters for "departingScopes" and "departingState" (or had access to them) it could make the decisions on what to carry forward and how.

@lmessinger
Copy link
Contributor

one option is to patch (which is what I resorted to) as follows:
function transitionTo(to, toParams, updateLocation,reloadOnSearch) {
if (!isDefined(updateLocation)) updateLocation = true;
if (!isDefined(reloadOnSearch)) reloadOnSearch = false /or true, up to you/;

not sure if it'll make sense for you or maybe even for a pull (@ksperling?)

@ksperling
Copy link
Contributor

@stu-salsbury Just to clarify the current behaviour, parent views are only reloaded if a parameter value belonging to that state is changed, i.e. if you navigate from http://angular-ui.github.io/ui-router/sample/#/contacts/42 to http://angular-ui.github.io/ui-router/sample/#/contacts/1 in the sample app, the outer 'contacts.html' template and associated controller are NOT reloaded/recreated. This is intentional and is not going to change.

What this issue is about is keeping some views (i.e. controllers + templates) around even when the associated parameters DO change, and having some ability for the controller to detect and handle that change itself.

@laurelnaiad
Copy link

@ksperling: gotcha -- thanks very much for clarifying... that sounds very
useful, too :)

@carloc
Copy link

carloc commented May 24, 2013

@ksperling that last comment was VERY interesting and was the reason I started using ui-router straight away (I'm new to angular, doing my first project).
I can see that this is the case because I'm looking also at the backend log and I see that when changing a parameter that causes a reload of a single view, only the queries related to it are carried out.
The one thing I don't understand, though, is why my page scrolls back up. Using your example, if the contacts.list view becomes too long to cause scrolling, when clicking on a contact the page would scroll back up. Is there any way to avoid this behavior?
I hope you can understand my concerns, sorry for my english!
Keep up the good work! ;)

@timkindberg
Copy link
Contributor

scrolling is being discussed here in #110

@carloc
Copy link

carloc commented May 24, 2013

Thank you very much! 👍

@stasgrom
Copy link
Author

I'd like to follow up on this issue, as we're desperately in need of this functionality.

I saw that in the roadmap of the project there's a mentioning of implementing the "reload=false". Is this the support to not reload the state if a URL parameter changes? If yes, great! When do you think this API will become available?

Thanks.

@nateabele
Copy link
Contributor

@stasgrom It'll become available as soon as someone has time to implement it. If you'd like to help, you can find me in the #angularjs IRC channel on Freenode.

@nateabele
Copy link
Contributor

Redirecting this discussion to #125, which covers complex parameters, parameter typing, and configurable reloads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants