Backbone: History.navigate should allow setting of state object

Created on 28 Nov 2011  ·  11Comments  ·  Source: jashkenas/backbone

Currently History calls pushState with an empty {} state object. It's crucial to allow the caller to set the state object. At the very least using window.history.state if available would be a sensible default. History.navigate should take a stateObject as an additional parameter.

change wontfix

Most helpful comment

History API deals specifically with app state tied to the nav path, distinct from the URI. I.e. "How did we get here?" Maybe it should be called the Hysterisis API. We may share the same URI and be on the same 'page' but not the same return view/page/state when I hit the back button on the mouse or swipe back on your mobile. And that back action may change the app state/history without changing the URI. Not all nav transitions are URI transitions. So when we share a URI it may lead to presenting the same resource or 'page' but not the same nav state.

While I appreciate the experience of your flock, I think it just goes to show that most developers haven't yet figured out how to use the API as intended by the creators. That's not a good reason for the framework to pave it over.

Also, you didn't address the question, which was not how to persist the form values, but rather how to use the push/popState API to prompt the user to save the changes, if any, when they hit the back button to nav away from the form with the bookmarkable URI. Please consider addressing that.

All 11 comments

I'm afraid that I disagree -- but please try to persuade me otherwise.

The point of the History API is to provide bookmarkable, shareable URLs, that you can navigate back to. If you attach a history object with the API, the page that you navigate back to _is not_ the same as the page that you would see if you pasted in the identical URL. This seems broken ... and at the very least redundant with your ability to store arbitrary state in JS during the course of a browser session.

It smells like an API where the browser implementors thought, "gee, wouldn't it be neat if you could...", and didn't consider the real consequences.

I think you are making assumptions about desirable app behavior and also the granularity of history events which are more restrictive than what the browser API provides. Specifically there's no reason it should be up to the framework and not the app to dictate the behavior when invoked with a URI. It seems perfectly and obviously legitimate that there is state (given by the navigation path) which is orthogonal to the resource (and encoded state) identified by the URI, and that the presentation is conditioned on both. Clearly that choice should be up to the individual app.

Aside from that abstract argument, tell me how would you implement for example a bookmarkable entry form that offers to save/discard changes when navigated away from (including with the back button) using the History API?

This is a one or two line change. If you don't want to add a parameter to History.navigate it could also be made to use the state given via e.g. a currentState attribute or function.

tell me how would you implement for example a bookmarkable entry form
that offers to save/discard changes when navigated away from (including
with the back button) using the History API?

I would simply store the form changes in a different and safer place: In the session, in the server, in localstorage...

I was curious about what folks thought of this position, so I asked:

https://twitter.com/jashkenas/status/142736117895151616

And here were some of the replies:

https://twitter.com/juandopazo/status/142737949178601472

https://twitter.com/yaypie/status/142737982879842304

https://twitter.com/fortes/status/142742305877659648

https://twitter.com/dyakovlev/status/142743995020349441

https://twitter.com/bassistance/status/142882410982420481

History API deals specifically with app state tied to the nav path, distinct from the URI. I.e. "How did we get here?" Maybe it should be called the Hysterisis API. We may share the same URI and be on the same 'page' but not the same return view/page/state when I hit the back button on the mouse or swipe back on your mobile. And that back action may change the app state/history without changing the URI. Not all nav transitions are URI transitions. So when we share a URI it may lead to presenting the same resource or 'page' but not the same nav state.

While I appreciate the experience of your flock, I think it just goes to show that most developers haven't yet figured out how to use the API as intended by the creators. That's not a good reason for the framework to pave it over.

Also, you didn't address the question, which was not how to persist the form values, but rather how to use the push/popState API to prompt the user to save the changes, if any, when they hit the back button to nav away from the form with the bookmarkable URI. Please consider addressing that.

I am very new to Backbone and WebDev in general, however I agree with tribalvibes.

I want to create a web application based on Facebook's Graph API and use Backbone's navigate function to allow the user to go back to different items to view at, similar to what Facebook does right now. However, without the stateobject in pushState, the user has to reload the item from the API, which is obviously costly.

It is probably because I dont know what the common pattern for this problem is, but I think having a state object for this would be very helpful.

Per the MDN documentation, the state object is saved to disk. I don't understand how that is any different than saving to local storage. I think this should be readdressed. Using local storage or another method of saving the state seems extraneous when you have the state object available to you in the history api.

Right, but contra: Using the state object should be extraneous when you have local storage, cookies, or any other method of saving state that's _not_ simply tied to the current URL.

Why wouldn't it be better to utilize the tool that's provided? The state object provides a straight forward method of saving and accessing previous states. Rather than sifting through local storage each time a user arrives at a page, having history.state available would allow the ability to recall not only the generic state of the view via the url route, but also the specific state of that view that a user might want to return to.

In my view, simple apps that use routes should use them simply. Copy and paste the url for the full experience. Complex apps should use routes only as simple entry points to general areas of the application, or particular records, and then use storage apis that better represent the type of persistence, whether it be user (server), session or local.

Using the history state object defeats what's great about the simple way single page apps can use urls as potentially permanent bookmarks.

Backbone has always been very flexible and less opinionated than other frameworks. I don't understand why this is different with the native window.history.pushState. I understand that some people won't like it. However, the decision of using it or not should be left to the final user.

So please, rethink it.

@rafayepes I'm fully agree with your argument. I love Backbone and its simplicity, but this API change introduces a bunch of problems and workarounds in the code, when the app should store 1-to-1 relationship between url and state. Native way of interacting with History API would be much much easier.

Was this page helpful?
0 / 5 - 0 ratings