Mercurial
Mercurial

Reputation: 3885

Access variable in Backbone View from Backbone Router

My router

var AppRouter = Backbone.Router.extend({
        routes: {
            ':*':'home',
            'home' : 'home',
            'home/:a' : 'home',
            '*whatever' : '404'

        },
        home: function (a) {
            document.title = siteTitle + ' - Home';
            homePage = new HomePage;
            homePage.render(a);
        },
        404: function(){
            document.title = siteTitle + ' - 404';
            fofPage = new FoFPage;
            fofPage.render();
        }

    });

My home view

var HomePage = Backbone.View.extend({
        initialize: function (options) {
            _.bindAll(this, 'beforeRender', 'render', 'afterRender');
            var _this = this;
            this.render = _.wrap(this.render, function (render) {
                _this.beforeRender();
                render();
                _this.afterRender();
                return _this;
            });
        },

        beforeRender: function () {
            console.log('beforeRender');
        },

        el: $('#indexcontent'),

        template: _.template(homeHTML, {}),

        render: function (a) {
            (a == null) ? Backbone.history.navigate('home'): Backbone.history.navigate('home/' + a);
            console.log('Passed parameter is ' + a);
            this.$el.html(this.template);

        },

        afterRender: function () {
            $('pre code').each(function (i, block) {
                hljs.highlightBlock(block);
            });
            console.log('afterRender');
        }
    });

I am trying to catch that variable a from router to view. But it shows undefined in my console. I tried fiddling with the variable options in the initialize but no luck. Thanks

Upvotes: 0

Views: 287

Answers (2)

Emile Bergeron
Emile Bergeron

Reputation: 17430

While you found an answer, I will explain why your initial code wasn't working and even more.

Why passing to render doesn't work?

Because you're overriding the render function in the initialize function with a wrapped version, using the underscore's wrap function.

It could work, but you'd need to take the parameter into account when wrapping:

this.render = _.wrap(this.render, function(render, a) {
    this.beforeRender();
    render.call(this, a); // here, pass the argument
    this.afterRender();
    return this;
});

Also notice that you don't need var _this = this as you're just replacing a member function and the context is applied automatically when called. Same thing for _.bindAll which is useless here.

The easier way

That wrap thing is unnecessary, it's only complexifying the HomePage view without any benefits or added features.

The only thing you'd need:

var HomePage = Backbone.View.extend({
    el: $('#indexcontent'),

You can ignore the options param (the {})

    template: _.template(homeHTML),

    initialize: function(options) {

if you want to pass options to initialize, use one of the following patterns:

        this.options = options || {}; // make sure it's an object.

or, better, make sure it's a copy of the object, with default values.

        this.options = _.extend({
            route: "default-value"
        }, options);
    },

    beforeRender: function() {
        console.log('beforeRender');
    },

    render: function(route) {
        this.beforeRender();

Do the redirection in the router, it's his role.

        // (a == null) ? Backbone.history.navigate('home'): Backbone.history.navigate('home/' + a);

        console.log('Passed parameter is ' + route || this.options.route);

The underscore's _.template function returns a function, so you need to call it.

        this.$el.html(this.template());

        this.afterRender();
        return this;
    },

    afterRender: function() {

Avoid the global jQuery function and prefer scoping your search to the view element and its children with this.$(selector).

        this.$('pre code').each(function(i, block) {
            hljs.highlightBlock(block);
        });
        console.log('afterRender');
    }
});

Upvotes: 2

Mercurial
Mercurial

Reputation: 3885

var AppRouter = Backbone.Router.extend({
        routes: {
            ':*':'home',
            'home' : 'home',
            'home/:a' : 'home',
            '*whatever' : '404'

        },
        home: function (a) {
            document.title = siteTitle + ' - Home';
            homePage = new HomePage({route: a});
            homePage.render();
        },
        404: function(){
            document.title = siteTitle + ' - 404';
            fofPage = new FoFPage;
            fofPage.render();
        }

    });

View

var HomePage = Backbone.View.extend({
        initialize: function (options) {
            this.options = options;
            _.bindAll(this, 'beforeRender', 'render', 'afterRender');
            var _this = this;
            this.render = _.wrap(this.render, function (render) {
                _this.beforeRender();
                render(_this.options['route']);
                _this.afterRender();
                return _this;
            });
        },

        beforeRender: function () {
            console.log('beforeRender');
        },

        el: $('#indexcontent'),

        template: _.template(homeHTML, {}),

        render: function (a) {
            (a == null) ? Backbone.history.navigate('home'): Backbone.history.navigate('home/' + a);
            console.log('Passed parameter is ' + a);
            this.$el.html(this.template);

        },

        afterRender: function () {
            $('pre code').each(function (i, block) {
                hljs.highlightBlock(block);
            });
            console.log('afterRender');
        }
    });

Upvotes: 1

Related Questions