0

I'm using Backbone inside a PhoneGap application. Like every mobile app I need a back-button functionality. It's basically working perfectly with Backbone, because I can simply use window.history.back() and it just works.

The only problem I have is to decide when to display the back button. Using window.history.length does not work, because it's not decremented when using back() (of course, because you can go forward() as well).

Is there any way to detect if there's more history or if I'm already at the bottom of the stack? Since the browser doesn't seem to supply this info (How to check if the user can go back in browser history or not) does Backbone keep track of this maybe?

Community
  • 1
  • 1
Prinzhorn
  • 22,120
  • 7
  • 61
  • 65

3 Answers3

4

You can implement something like this pretty easily

Backbone.history.length = 0;
Backbone.history.on('route', function () { ++this.length; });
myRouter.back = function () {
  Backbone.history.length -= 2;
  window.history.back();
};

And just use myRouter.back() to go back.

Casey Foster
  • 5,982
  • 2
  • 27
  • 27
  • This is how I do it as well, and it works as long as you can control the back navigation. I doesn't work if the user can navigate backwards with the browser's native back button or a phone hardware button, though. – jevakallio Jan 30 '13 at 16:06
  • @casey-foster One problem: When using `{replace:true, trigger: true}` you're screwed – Prinzhorn Jan 30 '13 at 16:29
  • I used this solution in order to determine if the route was a brand new browser session/tab or not. if (length) { /*existing browser tab session*/ } else { /* brand new browser tab session */ } – Ken Jun 03 '15 at 20:53
2

Casey Foster's answer looks nice on first sight, but has a flaw: When using router.navigate with trigger and replace both set to true you'll end up with a wrong counter.

I came up with a much simpler solution: Basically there's only one route where I don't need a back-button and that's the index route. Thus my code now looks like

Backbone.history.on('route', _.bind(function(router, route) {
    if(route === 'index') {
        this.$el.removeClass('has-back-button');
    } else {
        this.$el.addClass('has-back-button');
    }
}, this));
Prinzhorn
  • 22,120
  • 7
  • 61
  • 65
  • `index` -> `another page` -> `index`, you can't go back to `another page` via `window.history.back()` right? – Casey Foster Jan 30 '13 at 16:51
  • You can only get to `index` using the back-button. Index contains a list. You open an item (and maybe sub-items) and use the back-button to get back to the list. So it works perfectly for my use case. – Prinzhorn Jan 30 '13 at 16:53
  • Hey if it satisfies your use case that's all you need then. A tip, if you're using BB >= 0.9.9, you can write `this.listenTo(Backbone.history, 'route', function (__, route) { ... });` without having to `_.bind` the function. This also makes event clean-up easy (and automatic in `View#remove`) with `this.stopListening()`. – Casey Foster Jan 30 '13 at 16:59
  • @CaseyFoster Thanks, I almost forgot about `listenTo` (came across it once). – Prinzhorn Jan 30 '13 at 17:05
0

Building on @CaseyFoster's answer, you can keep track of the history yourself. In addition to your own back button you need to catch the device's hardware Back-button press.

PhoneGap provides the backbutton event for this:

document.addEventListener("backbutton", function() {
  Backbone.history.length -=2;
}, false);

Notice that Backbone.history.length is defined in Casey Foster's answer, it's not a part of Backbone itself.

Community
  • 1
  • 1
jevakallio
  • 35,324
  • 3
  • 105
  • 112