Bernie
Bernie

Reputation: 5055

Confusing this.el in backbone.js with subviews

I've a big problem with subviews in backbone.js. I've two views and I want to render the second one into an element of the first one. So i defined this.el in the second view which is referenced to a section (section#user-data) in the first view.

I create an object of the second view after first view has been rendered and if i write alert($('#user-data').length) before I create my object I get a 1 so it exists.

But inside the second view I get an undefined. If I log this.el in any method. But if I use e.g. body for this.el everything works as expected.

What's the reason for that?

Example:

   /**
     * The example of a view for profile's component
     *
     *
     * @module Profile
     * @submodule Frontend
     * @class ProfileView
     * @constructor
     *
     */
    ProfileView = Backbone.View.extend({

        // The tagname wrapping the rendered content
        // The template for the current view
        template : _.template('COMPONENTS_VIEW_FRAME'),

        /**
         * The initialisation for the current view (kind of constructor)
         *
         * @method initialize
         */
        initialize : function() {
        },

        /**
         * The rendering process for the current view
         *
         * @method render
         * @param {String} oLocas the data to render inside this view
         */
        render : function(oLocas) {

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

            return this;
        }
    });

           /**
     * The example of a view for profile's component
     *
     *
     * @module Profile
     * @submodule Frontend
     * @class ProfileView
     * @constructor
     *
     */
    ProfileSectionView = Backbone.View.extend({

        // The tagname wrapping the rendered content

        // The template for the current view
        template : _.template('COMPONENTS_VIEW_OPTION_SECTION'),

        el : $('#user-data'),

        events : {
            'click a.open_close_section' : 'doIt'
        },

        headline : 'ddd',

        /**
         * The initialisation for the current view (kind of constructor)
         *
         * @method initialize
         */
        initialize : function() {
            alert($(this.el).length);
        },

        doIt : function(event) {
            alert('jo');
        },

/**
         * The rendering process for the current view
         *
         * @method render
         * @param {String} eventName the name of the triggered event
         */
        render : function(oLocas) {

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

            return this;
        }
    });
            // Here I start to use the first view
            var oProfileView = new ProfileView();

                $('#profile').html(oProfileView.render().el).fadeIn(500,    function() {

                    $(this).removeClass('closed');
                                            // Here I create the second view
                    var oProfileSectionView = new ProfileSectionView({
                        model : this.model
                    });

                    oProfileSectionView.render({
                        headline : 'XXX',
                        sectionrows : 'ddd'
                    }).el;

                });

Upvotes: 2

Views: 255

Answers (1)

Kevin Peel
Kevin Peel

Reputation: 4090

This is a little gotcha with JavaScript.

JavaScript is looking for that element when you're defining ProfileSelectionView. So this:

ProfileSectionView = Backbone.View.extend({
    // ...
    el : $('#user-data'),
    // ...
});

Is actually being evaluated right there in the definition of ProfileSelectionView, not later on when you instantiate an instance of ProfileSelectionView.

To fix this, move the defining of el into the initialization:

ProfileSectionView = Backbone.View.extend({
    // ...
    // Do not define the el here. I've commented it out
    // el : $('#user-data'),
    // ...
    initialize : function() {
        this.setElement($('#user-data'));
    },
    // ...
});

Or even better, you can just pass the element in when creating the ProfileSelectionView (as noted in the Backbone.js docs):

var oProfileView = new ProfileView();

$('#profile').html(oProfileView.render().el).fadeIn(500,    function() {
    // ...
    var oProfileSectionView = new ProfileSectionView({
        model : this.model,
        el: $('#user-data')
    });
    // ...
});

By doing it this way, you don't have to define an initialize function in ProfileSelectionView.

Upvotes: 4

Related Questions