Search code examples
javascriptjquerybackbone.js

Following URLS in backbone.js on div click


I have started to get familiar with backbone.js and needed a little time to wrap my head around routers, models and views.

Handling routes through router and defining them are piece of cake, until that particular route is defined as <a href="#some-url"> (I am not sure 100%, but I presume backbone is overriding default link behavior and instead redirecting it dynamically load templates staying on current page).

What I need is acton that is executed on user clicking on div element. It was easy to add event under view, and clicking on the div correctly called the function.

But from that point I was uncertain what to do. I can easily add: window.location.href = "#some-url", and browser will redirect page to asked href, but that seems as breaking one-pager rules backbone is trying to create.

Is there a more appropriate way to handle views change than forcing browser to change href via window.location ?

EDIT: added the code.

app.js

require(['jquery', 'backbone', 'app/router'], function ($, Backbone, Router) {
    window.router = new Router();   
    Backbone.history.start();
});

app/router.js

var $           = require('jquery'),
    Backbone    = require('backbone'),
    HomeView    = require('app/views/Home'),
    $body = $('body'),
    homeView = new HomeView({el: $body});
...  
return Backbone.Router.extend({

    routes: {
        "": "home",
        "about": "about"
     },

    home: function () {
        homeView.delegateEvents();
        homeView.render();
    },

    about: function () {
        require(["app/views/About"], function (AboutView) {
            var view = new AboutView({el: $body});
            view.render();
        });
    },

...

app/router/views/home.js

return Backbone.View.extend({

    events: {
      "click #about": "followAbout"
    },
    render: function () {
        this.$el.html(template());
        return this;
    },
    followAbout: function () {
       console.log('about');
       window.router.navigate( "about", { trigger: true } )
    }
});

Solution

  • Lets say you've defined your router like this

     var Workspace = Backbone.Router.extend({
       routes: {
         "help":                 "help",    // #help
         "search/:query":        "search",  // #search/kiwis
         "search/:query/p:page": "search"   // #search/kiwis/p7
       },
       help: function() {
         ...
       },
       search: function(query, page) {
         ...
       }
     });
    

    And then created a new instance of your router

    router = new Workspace();
    Backbone.history.start();
    

    In your div you can optionally define your route in a data attribute, which will be convenient for you like this

    <div id="my_div" data-path="some-url">
      ...
    </div>
    

    When the user will click the div, you take the route from its data and use navigate function to go to that route like this.

    $("#my_div").on('click', function(e){
      var path = $(this).attr("data-path");
      router.navigate(path, { trigger: true});
      //this will navigate to the path like a single page app without reloading the page
    });
    

    Checkout backbone docs for more.

    Edit

    ...
    //events inside first view
    'click #div-1': 'myFunction'
    
    //myfunction code
    myFunction: function(e){
      clicked_div = e.currentTarget;
      path = $(clicked_div).attr('data-path'); //I'm assuming you've stroed the path in your div, or you can get it how ever you like
    
      window.router.navigate(path, {trigger: true});
      //Also I am assuming you've defined your router under the window object directly, so it can be accessed directly. Or you can always namespace it in an object
      //, to avoid collision
    }