Question

I have setup a main navigation menu with 4-5 anchors and the related views. Its the typical "home", "about", "news" etc menu. In one of the views, lets say "news" there is an additional menu with 3 anchors, lets say "national", "international" and "others", when you click those, it displays the related view inside the "news" view and its only supposed to be displayed there. So far so good. But then, when i click on "about" anchor on the main navigation, it shows me the about view, but also still the additional menu from the "news" view and of course I don't want that. So, what to do here?

[UPDATE]: I made some changes, but still it does not work!

I added backbone.view-prototype code into my mainpage.js:

define(function (require) {

'use strict';

Backbone.View.prototype.close = function(){
    this.remove();
    this.unbind();
    if (this.onClose){
        this.onClose();
    }
}

var AppRouter = require('../app/routers/router');

$(function () {

    var App = new AppRouter();

});

});

and i added the close function into my view:

define(['backbone','handlebars', 'text!templates/News.html'],



    function(Backbone,Handlebars, Template) {

        'use strict';


        var NewsView = Backbone.View.extend({

            template: Handlebars.compile(Template),

            events: {
            },

            initialize: function () {
                _.bindAll(this);
            },

            render: function() {
                $(this.el).html(this.template());
                return this;
            },

            close: function(){
                this.remove();
                this.unbind();
            }

        });

        return NewsView;    

    }
 );

My router looks like this (short version):

        var Router = Backbone.Router.extend({

        routes: {
            '': 'index',
            'pages/about' : 'about',
            'pages/news' : 'news',
            'pages/news/national' : 'national',
            'pages/news/international' : 'international',
            'pages/news/other' : 'other',
            'pages/contact' : 'contact'
        },

        //Initializing the application
        initialize: function () {
            var self = this;

            //Collections
            this.mainMenuCollection = new MainMenuCollection();
            this.newsMenuCollection = new NewsMenuCollection();

            //Views
            this.mainMenuView = new MainMenuView({el:'#mainMenu', collection:this.mainMenuCollection});

            this.mainMenuCollection.fetch({success: function(collection) {
                self.mainMenuView.collection=collection;
                self.mainMenuView.render();
            }});

            this.newsMenuCollection.fetch({success: function(newscollection) {
                self.newsMenuView.newscollection=newscollection;
                self.newsMenuView.render();
            }});

            Backbone.history.start({
                pushState: false
            });

        },

        //Default route.
        index: function () {
            var self = this;
        },

        about: function() {
            this.aboutView = new AboutView({el:'#topContent'}).render();
        },

        news: function() {
            this.newsView = new NewsView({el:'#topContent'}).render();
            this.subMenuView = new SubMenuView({el:'#subMenu', collection:this.subMenuCollection}).render();
        },


        about: function() {
            this.aboutView = new AboutView({el:'#topContent'}).render();
        },

        contact: function() {
            this.contactView = new ContactView({el:'#topContent'}).render();
        },

        national: function() {
            this.nationalView = new NationalView({el:'#subContent_2'}).render();
        },

        international: function() {
            this.internationalView = new InternationalView({el:'#subContent_2'}).render();
        },

        other: function() {
            this.otherView = new OtherView({el:'#subContent_2'}).render();
        }                       


    });

    return Router;
}
Was it helpful?

Solution

Ok lets simplify what you are trying to achieve:

  • Go to 'News' route, add additional menu
  • Move away from 'News' route, remove the news sub-menu

Now in vanilla Backbone, the only way to do is to do it manually. Something like this:

var Router = Backbone.Router.extend({       

        onBeforeRoute: function () {
            if (this.subMenuView) this.subMenuView.$el.empty();

            // anything else you need to do
        },

        ...

        //Default route.
        index: function () {
            this.onBeforeRoute();

            var self = this;
        },

        about: function() {
            this.onBeforeRoute();           

            this.aboutView = new AboutView({el:'#topContent'}).render();
        },

        news: function() {
            this.onBeforeRoute();

            this.newsView = new NewsView({el:'#topContent'}).render();
            this.subMenuView = new SubMenuView({el:'#subMenu', collection:this.subMenuCollection}).render();
        },

        ...
}

Check out the docs here to see about the remove method.

One other thing I would suggest, is instantiating your views in your initialize method. If you keep recreating them every time a route is fired, the old views hang around in memory and are still bound to the DOM, causing strange issues if your views are bound to data etc. I can see you have something happening to stop this in the close method you have implemented, but it looks like you're not actually calling it anywhere.

Also, I would say it is frustrating when you first try to get to grips with Backbone, but stick with it, and keep reading articles on best practices etc, cause you always need to remember that Backbone IS NOT A FRAMEWORK! It is a very simple library, it offers nothing really in the way of conventions or ways to structure your application (which is why many people like it). I love Backbone but I actually use it along with Marionette, which provides a lot of nice ways to structure your application. I recommend checking it out.

OTHER TIPS

this looks like similar issue to this: Backbone Router on any page change event

You can use Routefilter plugin, and define before function, which can cleanup views, that should no longer be visible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top