Search code examples
javascriptbackbone.js

How to switch view using router in backbone.js


I faced the problem that view switches with router.

My application is written with Backbone.js. It has 2 views, ApplicationView and ApplicationSubView.

Originally, I thought that if occurred click event then through router should move the page

For example, anyone who clicked the element having the about class then must exprience moved and re-rendered pages

var app = app || {};
$(function() {
    'use strict';
    var ApplicationView = Backbone.View.extend({
        //bind view to body element (all views should be bound to DOM elements)
        el: $('body'),
        //called on instantiation
        initialize: function() {
            //set dependency on ApplicationRouter
            this.router = app.Router;
            this.subView = new ApplicationSubView();
            //call to begin monitoring uri and route changes
            Backbone.history.start();
        },
        showSpinner: function() {
            console.log('show the spinner');
        },

        hideSpinner: function() {
            console.log('hide the spinner');
        },
        loadSubView: function() {
            this.showSpinner();
            var subView = new SubView();
            subView.on('render', this.hideSpinner);
        }
    });

    var ApplicationSubView = Backbone.View.extend({
        events: {
            'click ul.pills li.home-pill a': 'displayHome',
            'click ul.pills li.about-pill a': 'displayAbout',
            'click ul.pills li.contact-pill a': 'displayContact'
        },

        displayHome: function() {
            this.trigger('render');
            console.log('a subView render');
            this.router.navigate("home", true);
            return this;
        },

        displayAbout: function() {
            this.trigger('render');
            console.log('a subView render');
            this.router.navigate("about", true);
            return this;
        },

        displayContact: function() {
            this.trigger('render');
            console.log('a subView render');
            this.router.navigate("contact", true);
            return this;
        }
    });
    //load application
    app.view = new ApplicationView();
});

Solution

  • While I can't really understand the question's description, I can see a lot of improvements that needs to be done so I've made a complete refactor of your code.

    Routing is just handling changes in the URL, so you can use anchor tags directly, without explicit events and navigate calls.

    This is all you'd need to trigger the routes.

    <body>
        <ul class="pills">
            <li><a href="#/">Home</a></li>
            <li><a href="#/about">About</a></li>
            <li><a href="#/contact">Contact</a></li>
        </ul>
        <div id="content"></div>
    </body>
    

    See the <div id="content"></div>? This is the content div and this is where the other pages will go. We'll manage that using a "layout" view:

    var app = app || {};
    (function() {
        'use strict';
        var views = app.view = app.view || {};
        views.Application = Backbone.View.extend({
            initialize: function() {
                // caching the jQuery object on init
                this.$content = this.$('#content');
            },
            setContent: function(view) {
                var content = this.content;
                if (content) content.remove();
                content = this.content = view;
                this.$content.html(content.render().el);
            },
        });
    
        // make a view for each sub-page
        views.Home = Backbone.View.extend({ /* ... */ });
        views.About = Backbone.View.extend({ /* ... */ });
        views.Contact = Backbone.View.extend({ /* ... */ });
    })();
    

    Then, you need to define a router that handles these routes.

    var app = app || {};
    (function() {
        'use strict';
        var views = app.view = app.view || {};
    
        app.Router = Backbone.Router.extend({
            routes: {
                'about': 'aboutRoute',
                'contact': 'contactRoute',
                // put the catch-all last
                '*home': 'homeRoute',
            },
            initialize: function() {
                // create the layout once here
                this.layout = new views.Application({
                    el: 'body',
                });
            },
            homeRoute: function() {
                var view = new views.Home();
                this.layout.setContent(view);
            },
            aboutRoute: function() {
                var view = new views.About();
                this.layout.setContent(view);
            },
            contactRoute: function() {
                var view = new views.Contact();
                this.layout.setContent(view);
            }
        });
    })();
    

    And to use it when the document is ready:

    $(function() {
        var router = new app.Router();
        Backbone.history.start();
    });