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

can.route - Allow changing the route (and URL) without saving to browser history #1137

Closed
jondubois opened this Issue Jul 1, 2014 · 4 comments

Comments

Projects
None yet
3 participants
@jondubois
Contributor

jondubois commented Jul 1, 2014

I'm working on a relatively complex 'single page' app which implement its own client-side page switching (with transitions).

I researched can.route and the pushstate plugin but I wasn't able to find a way to use can.route to change the hash part of the URL without affecting the history.
Consider the following scenario:

A user is on a page and they click a button which causes part (but not all) of the page's content to be updated with new data. They might click through many such buttons. Now if they press the back button, I want to take them back to the previous 'proper' page - Not the previous state (there might be a LOT of such states not related to page changes and it would be tedious to make them click back 50 times to get to the actual 'previous page' - Especially if they navigate back and forth between buttons). When they click on a button, I still need to update the URL in case they want to bookmark the app's exact state or share it with someone else.

I had to add some workaround code that made use of history.replaceState() to get this behaviour working - It would be great if there had been an option you could set when calling can.route.attr(attrName, value) which would let you not save that particular route to history (but otherwise should behave the same).

Maybe this already exists but I wasn't able to find any documentation.

@justinbmeyer

This comment has been minimized.

Show comment
Hide comment
@justinbmeyer

justinbmeyer Jul 1, 2014

Contributor

What would this look like? Please propose an API.

Sent from my iPhone

On Jul 1, 2014, at 1:08 AM, Jonathan Gros-Dubois notifications@github.com wrote:

I'm working on a relatively complex 'single page' app which implement its own client-side page switching (with transitions).

I researched can.route and the pushstate plugin but I wasn't able to find a way to use can.route to change the hash part of the URL without affecting the history.
Consider the following scenario:

A user is on a page and they click a button and that button causes part (but not all) of the page's content to be updated with new data. They might click through many such buttons. Now if they press the back button, I want to take them back to the previous 'proper' page - Not the previous app state (there might be a LOT of such states not related to page changes and it would be tedious to make them click back 50 times to get to the actual 'previous page'). When they click on a button, I still need to update the URL in case they want to bookmark the app's state or share it with someone else.

I had to add some workaround code that made use of history.replaceState() to get this behaviour working - It would be great if there had been an option you could set when calling can.route() which would let you not save that particular route to history (but otherwise should behave the same).

Maybe this already exists but I wasn't able to find any documentation.


Reply to this email directly or view it on GitHub.

Contributor

justinbmeyer commented Jul 1, 2014

What would this look like? Please propose an API.

Sent from my iPhone

On Jul 1, 2014, at 1:08 AM, Jonathan Gros-Dubois notifications@github.com wrote:

I'm working on a relatively complex 'single page' app which implement its own client-side page switching (with transitions).

I researched can.route and the pushstate plugin but I wasn't able to find a way to use can.route to change the hash part of the URL without affecting the history.
Consider the following scenario:

A user is on a page and they click a button and that button causes part (but not all) of the page's content to be updated with new data. They might click through many such buttons. Now if they press the back button, I want to take them back to the previous 'proper' page - Not the previous app state (there might be a LOT of such states not related to page changes and it would be tedious to make them click back 50 times to get to the actual 'previous page'). When they click on a button, I still need to update the URL in case they want to bookmark the app's state or share it with someone else.

I had to add some workaround code that made use of history.replaceState() to get this behaviour working - It would be great if there had been an option you could set when calling can.route() which would let you not save that particular route to history (but otherwise should behave the same).

Maybe this already exists but I wasn't able to find any documentation.


Reply to this email directly or view it on GitHub.

@jondubois

This comment has been minimized.

Show comment
Hide comment
@jondubois

jondubois Jul 2, 2014

Contributor

@justinbmeyer - Maybe something along the lines of can.route.attr(key, value[, options]) - The options object could hold property names (I.e.. a 'history' property in this case) to let you customize how can.route should handle the attribute change.

For example:

// Overwrite the previous history entry
can.route.attr('contentId', id, {history: 'replace' })

// Do not add this route to history at all
can.route.attr('contentId', id, {history: 'ignore' })

I realize that this somewhat violates the simplicity (and consistency) of the attr() method so maybe it's not ideal. But then again, functionality-wise, can.route's attr() method does more than that of can.Map, so maybe having an extra argument is justified?

The other alternative I can think of is to add a can.route.navigate(attrName, value, history)
method where the history argument is either 'replace' or 'ignore'... This is not perfect either semantically.

Contributor

jondubois commented Jul 2, 2014

@justinbmeyer - Maybe something along the lines of can.route.attr(key, value[, options]) - The options object could hold property names (I.e.. a 'history' property in this case) to let you customize how can.route should handle the attribute change.

For example:

// Overwrite the previous history entry
can.route.attr('contentId', id, {history: 'replace' })

// Do not add this route to history at all
can.route.attr('contentId', id, {history: 'ignore' })

I realize that this somewhat violates the simplicity (and consistency) of the attr() method so maybe it's not ideal. But then again, functionality-wise, can.route's attr() method does more than that of can.Map, so maybe having an extra argument is justified?

The other alternative I can think of is to add a can.route.navigate(attrName, value, history)
method where the history argument is either 'replace' or 'ignore'... This is not perfect either semantically.

@justinbmeyer

This comment has been minimized.

Show comment
Hide comment
@justinbmeyer

justinbmeyer Jul 23, 2014

Contributor

In keeping with how can.route is supposed to work, having a different .attr() signature might not be the best idea (although it would work).

can.route is designed to behave just like a normal can.Map, but have a side effect of updating the url. A widget should be largely ignorant if it is using can.route or another can.Map.

It seems to me that "some" changes you'd want to have the history change and others not. Maybe it's possible to signal this some other way.

I'm not proposing this API, but just to show you what I mean:

can.route.ignoreHistoryOn("contentId","visible","login");

This would use replaceState if those attributes changed.

Any thoughts on this?

Contributor

justinbmeyer commented Jul 23, 2014

In keeping with how can.route is supposed to work, having a different .attr() signature might not be the best idea (although it would work).

can.route is designed to behave just like a normal can.Map, but have a side effect of updating the url. A widget should be largely ignorant if it is using can.route or another can.Map.

It seems to me that "some" changes you'd want to have the history change and others not. Maybe it's possible to signal this some other way.

I'm not proposing this API, but just to show you what I mean:

can.route.ignoreHistoryOn("contentId","visible","login");

This would use replaceState if those attributes changed.

Any thoughts on this?

@justinbmeyer justinbmeyer added this to the 2.2.0 milestone Jul 23, 2014

@jondubois

This comment has been minimized.

Show comment
Hide comment
@jondubois

jondubois Jul 24, 2014

Contributor

Actually yes, something like that should work well.
There should probably also be an equivalent ignoreHistoryOff() method. I think history should be enabled by default though - Most routes do need the history.

Alternatively, the history-tracking status of each route could be a config option passed to can.route(). I think generally, the history behavior won't change at runtime anyway. Both techniques are equivalent for my particular use case.

Contributor

jondubois commented Jul 24, 2014

Actually yes, something like that should work well.
There should probably also be an equivalent ignoreHistoryOff() method. I think history should be enabled by default though - Most routes do need the history.

Alternatively, the history-tracking status of each route could be a config option passed to can.route(). I think generally, the history behavior won't change at runtime anyway. Both techniques are equivalent for my particular use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment