0

I am having difficulty with something very simple in Backbone. I want to wire up the <h1> in my page so that when the user clicks on it, it returns seamlessly to the homepage, without a postback.

This is the HTML:

<h1><a id="home" href="/">Home</a></h1>

(UPDATE: fixed ID as suggested by commenter.) And this is my Backbone view and router:

var HomeView = Backbone.View.extend({
  initialize: function() { 
    console.log('initializing HomeView');
  },
  events: { 
    "click a#home": "goHome"
  }, 
  goHome: function(e) { 
    console.log('goHome');
    e.preventDefault();
    SearchApp.navigate("/");
  }
});
var SearchApp = new (Backbone.Router.extend({
  routes: { 
    "": "index", 
  },
  initialize: function(){
    console.log('initialize app');
    this.HomeView = new HomeView();
  },
  index: function(){
    // do stuff here
  },
  start: function(){
    Backbone.history.start({pushState: true});
  }
}));
$(document).ready(function() { 
  SearchApp.start();
});

The console is showing me

initialize  app
initializing HomeView 

But when I click on the <h1>, the page posts back - and I don't see goHome in the console.

What am I doing wrong? Clearly I can wire up the <h1> click event simply enough in jQuery, but I want to understand how I should be doing it in Backbone.

Richard
  • 62,943
  • 126
  • 334
  • 542

2 Answers2

1

If you enable pushState you need to intercept all clicks and prevent the refresh:

$('a').click(function (e) {
  e.preventDefault();
  app.router.navigate(e.target.pathname, true);
});

Something like:

$(document).ready(function(){

  var HomeView = Backbone.View.extend({
    initialize: function() { 
      console.log('initializing HomeView');
    }
  });

  var AboutView = Backbone.View.extend({
    initialize: function() { 
      console.log('initializing AboutView');
    }
  });

  var AppRouter = Backbone.Router.extend({
    routes: { 
      "": "index", 
      "about":"aboutView"
    },

    events: function () {
      $('a').click(function (e) {
        e.preventDefault();
        SearchApp.navigate(e.target.pathname, true);
      });
    },

    initialize: function(){
      console.log('initialize app');
      this.events();
      this.HomeView = new HomeView();
    },

    index: function(){
      this.HomeView = new HomeView();
    },

    aboutView : function() {
      this.AboutView = new AboutView();
    }
  });

  var SearchApp = new AppRouter();
  Backbone.history.start({pushState: true});

});
Michael Mior
  • 28,107
  • 9
  • 89
  • 113
Sam3k
  • 960
  • 1
  • 11
  • 22
  • Where should I put that click handler within the backbone code? I know how to write a click handler in jQuery, but I don't know where to put it in Backbone. – Richard Jan 07 '13 at 15:37
  • I'm afraid the `Backbone.router.navigate` line in the router code above gives me an `Uncaught TypeError: Cannot call method 'navigate' of undefined`. I tried changing it to `Router` but that didn't help either. Finally, I changed it to `SearchApp.navigate` and that didn't throw an error, but it also didn't fire the `index` function. Think this is still wrong? I also am not clear why the `HomeView` view is even needed, if we can get `events()` to work properly. – Richard Jan 07 '13 at 15:52
  • What version of backbone do you have? Here is the docs: http://backbonejs.org/#Router-navigate Oh, you need to set the goHome method in the router, not the view. – Sam3k Jan 07 '13 at 15:52
  • Does SearchApp.start(); trigger initialize() ? – Sam3k Jan 07 '13 at 16:02
  • Should be Backbone.history.navigate, not Backbone.router.navigate. – Lukas Jan 07 '13 at 16:34
  • I've edited the code one last time. This one I tested it and it navigates to the right view without refreshing the page + using pushState. – Sam3k Jan 07 '13 at 16:50
  • I'm afraid this still doesn't work for me with Backbone 0.9.9 and Chrome/MacOS, and the code doesn't look quite right (e.g. it initialises HomeView twice). So I'm leaving the question open for now. Thanks for your help, anyway. – Richard Jan 07 '13 at 17:06
  • Hey Richard, hmm, it's weird. I've just created this jsfiddle for ya: http://jsfiddle.net/C7bmX/ The "app" div starts with the text "Loading..." and as soon as the router starts, it hits the initialize function which in turns executes the home view. The homeview renders the new html text "Welcome Home" If you click "about", the click event does not happen as we overrode it, but we do manually trigger the about route using backbone's navigate. – Sam3k Jan 07 '13 at 18:28
  • 2
    Thanks. I ended up using this code from Artsy, and putting it where you suggested: http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/ – Richard Jan 08 '13 at 15:19
  • @Richard and anyone else having trouble with this solution: A key difference between artsy's example and the code in this answer is using `$(document).on('click', 'a', ...)` instead of `$('a').click`. These would seem to be equivalent, however only the former worked for me and not the latter, as in this answer. – Trindaz Jun 23 '14 at 12:44
1

Your tag id is invalid, try this:

<h1><a id="home" href="/">Home</a></h1>
kdrvn
  • 1,009
  • 1
  • 7
  • 10