Search code examples
javascriptbackbone.jsmarionettebackbone-routing

Browser's back button break my Backbone / Marionette app


I'm building a web app using Backbone and Marionette with Ruby on Rails on the server.

The app works great, except for the back button of back browser (FF, Chrome, IE11) that breaks everything.

Here is a really simple example that reproduce the problem:

var TestApp = new Marionette.Application();

TestApp.addRegions({
	mainRegion: "#main-region"
});

TestApp.navigate = function(route, options){
	options || (options = {});
	Backbone.history.navigate(route, options);
};

TestApp.getCurrentRoute = function(){
	return Backbone.history.fragment
};

TestApp.on("start", function(){
	if(Backbone.history){
		Backbone.history.start();
		if(this.getCurrentRoute() === ""){
			this.navigate("foo");
			TestApp.MyApp.Show.Controller.ShowFoo();
		}
	}
});

TestApp.module("MyApp", function(App, TestApp, Backbone, Marionette, $, _) {
	App.Router = Marionette.AppRouter.extend({
		appRoutes: {
			"foo": "ShowFoo",
			"bar": "ShowBar",
			"baz": "ShowBaz"
		}
	});
	
	var API = {
		ShowFoo: function(){
			App.Show.Controller.ShowFoo();
		},
		ShowBar: function(){
			App.Show.Controller.ShowBar();
		},
		ShowBaz: function(){
			App.Show.Controller.ShowBaz();
		}
	};
	
	TestApp.addInitializer(function(){
		new App.Router({
			controller: API
		});
	});
});

TestApp.module("MyApp.Show", function(Show, App, Backbone, Marionette, $, _)
{
	Show.FooLayoutView = Backbone.Marionette.LayoutView.extend({
		template: "#templates-foo",
		tagName: "span"
	});
	Show.BarLayoutView = Backbone.Marionette.LayoutView.extend({
		template: "#templates-bar",
		tagName: "span"
	});
	Show.BazLayoutView = Backbone.Marionette.LayoutView.extend({
		template: "#templates-baz",
		tagName: "span"
	});

	var ContactsShowController = Marionette.Controller.extend({
		ShowFoo: function()
		{
			this.fooView = new Show.FooLayoutView();
			
			App.mainRegion.show(this.fooView);
		},
		ShowBar: function()
		{
			this.barView = new Show.BarLayoutView();
			
			App.mainRegion.show(this.barView);
		},
		ShowBaz: function()
		{
			this.bazView = new Show.BazLayoutView();
			
			App.mainRegion.show(this.bazView);
		}
	});
	Show.Controller = new ContactsShowController;
});

$(function() {
	TestApp.start();
});
<h1>Test the browser's back button.</h1>

<div id="main-region"></div>

<script type="text/template" id="templates-foo">
	<p>
		F O O
	</p>

	<p>
		<a href="#bar">-&gt; Bar</a>
	</p>
</script>

<script type="text/template" id="templates-bar">
	<p>
		B A R
	</p>

	<p>
		<a href="#baz">-&gt; Baz</a>
	</p>
</script>

<script type="text/template" id="templates-baz">
	<p>
		B A Z
	</p>

	<p>
		Press the back button on your browser. You should go back to BAR, but the view is not shown.
	</p>
</script>
The above snippet probably doesn't work directly, you'd need to include Backbone and MarionetteJS.

I'm using these versions of the librairies:

  • underscore.js 1.7.0
  • backbone.js 1.1.2
  • backbone.marionette.js 2.2.2

So, if you load the app, you should see "F O O", click the link for Bar, the click the link for Baz. You should now be on the last page showing "B A Z". Now click on the back button on your browser. The url should change back to #bar wich it does, but you should also see "B A R", but the #main-region is empty.

How can I fix this?

I'm open to update the libraries. And frankly, I'm also on the edge of throwing backbone and marionette in the trash and recoding everything in good old javascript + jQuery... But I,d prefer not to.

Thanks for any help.

Guillaume


Solution

  • Update: Based on comments, it became evident that the culprit was a an add-on that came packaged with the OP's rails installation.

    I suggested that he remove the rails/turbolinks libraryin his project, as it seemed to be interfering with proper page-reload.


    Made a fiddle with your code and included the same libraries you posted. I didn't change a thing and it works like magic.

    I also used jQuery 2.1.0 What's your version? See the fiddle.