I have a Rails 3.2.3 app with Backbone.js and I’m using pushState on my Backbone.history.
The Problem
When I click on a link which goes to say ‘/foo’ to show appointment with ID: 1, then Backbone router gets to that first, which I can quickly see before Rails router takes over and complains that there is no route for /foo.
My Backbone.js code
Here is my backbone router.
window.AppointmentApp = new (Backbone.Router.extend({
routes: {
"": "index",
"foo": "foo",
"appointments": "index",
"appointments/:id": "show"
},
foo: function(){
$("#app").append("foo<br />");
},
initialize: function() {
this.appointments = new Appointments();
this.appointmentListView = new AppointmentListView({ collection: this.appointments });
this.appointmentListView.render();
},
start: function() {
Backbone.history.start({pushState: true});
},
index: function() {
$("#app").html(this.appointmentListView.el);
this.appointments.fetch();
},
show: function(id) {
console.log("Enter show");
}
}));
It should stay on the same page and attach a ‘foo’ to the end of the #app div, but it never does.
Backbone index viewer
window.AppointmentListView = Backbone.View.extend({
template: JST["appointments/index"],
events: {
"click .foo": function(){Backbone.history.navigate("foo");},
},
comparator: function(appointment){
return appointment.get('topic');
},
initialize: function(){
this.collection.on('reset', this.addAll, this);
},
render: function(){
this.$el.html(this.template);
this.addAll();
return this;
},
addAll: function() {
this.collection.forEach(this.addOne, this);
},
addOne: function(appointment){
var appointmentView = new AppointmentView({model: appointment});
this.$el.append(appointmentView.render().el);
}
});
app/assets/templates/appointments/Index.jst.ejs
<h1>Appointments</h1>
<a href="/foo" class="foo">Say Foo</a>
<a href=appointments/add>Add</a>
<div id="app"></div>
I was using pushState as it allows me to keep a history and the Back button functionality.
The Backbone.history.navigate doesn’t call my Backbone route, it calls the Rails route instead. How do I go about fixing this?
Should I be trying to setup Backbone to accept routes such as ‘appointments/1’ and taking control or do I have to use a click event with a Backbone.history.navigate call like above?
You need to return false from your
click .fooevent handler, otherwise the browser will continue as if you’d clicked the link normally and request the actual/foopage from the server.I think you’ve also got the call to
Backbone.history.navigate("foo");wrong –Backbone.historydoesn’t have anavigatefunction as far as I can see from the documentation. You should actually be calling .navigate on yourBackbone.Routerinstance, and passing in thetriggeroption to cause it to call trigger the route. For example:You may already know this but if you’re planning on using pushState then you should really update your server side to support all the URLs that your client side does. Otherwise if a user decides to copy & paste the URL into another tab, they will just run into rails complaining that there is no route.