Garrett
Garrett

Reputation: 11725

Backbone View Attribute set for next Instantiation?

I have a view that has a tooltip attribute. I want to set that attribute dynamically on initialize or render. However, when I set it, it appears on the next instantiation of that view instead of the current one:

    var WorkoutSectionSlide = Parse.View.extend( {      
        tag : 'div',
        className : 'sectionPreview',
        attributes : {},

        template : _.template(workoutSectionPreviewElement),

        initialize : function() {
//          this.setDetailsTooltip(); // doesn't work if run here either
        },

        setDetailsTooltip : function() {
            // build details
            ...

            // set tooltip
            this.attributes['tooltip'] = details.join(', ');
        },

        render: function() {            
            this.setDetailsTooltip(); // applies to next WorkoutViewSlide

            // build firstExercises images
            var firstExercisesHTML = '';
            for(key in this.model.workoutExerciseList.models) {
                // stop after 3
                if(key == 3)
                    break;
                else
                    firstExercisesHTML += '<img src="' +
                        (this.model.workoutExerciseList.models[key].get("finalThumbnail") ?
                                this.model.workoutExerciseList.models[key].get("finalThumbnail").url : Exercise.SRC_NOIMAGE) + '" />';
            }

            // render the section slide
            $(this.el).html(this.template({
                workoutSection : this.model,
                firstExercisesHTML : firstExercisesHTML,
                WorkoutSection : WorkoutSection,
                Exercise : Exercise
            }));


            return this;
        }
    });

Here is how I initialize the view:

// section preview
$('#sectionPreviews').append(
    (new WorkoutSectionPreview({
        model: that.workoutSections[that._renderWorkoutSectionIndex]
    })).render().el
);

How can I dynamically set my attribute (tooltip) on the current view, and why is it affecting the next view?

Thanks

Upvotes: 3

Views: 4477

Answers (2)

evilive
evilive

Reputation: 1869

You can define attribute property as a function that returns object as result. So you're able to set your attributes dynamically.

var MyView = Backbone.View.extend({
    model: MyModel,
    tagName: 'article',
    className: 'someClass',
    attributes: function(){
        return {
            id: 'model-'+this.model.id,
            someAttr: Math.random()
        }
    }
})

I hope it hepls.

Upvotes: 7

mu is too short
mu is too short

Reputation: 434606

I think your problem is right here:

var WorkoutSectionSlide = Parse.View.extend( {      
    tag : 'div',
    className : 'sectionPreview',
    attributes : {} // <----------------- This doesn't do what you think it does

Everything that you put in the .extend({...}) ends up in WorkoutSectionSlide.prototype, they aren't copied to the instances, they're shared by all instances through the prototype. The result in your case is that you have one attributes object that is shared by all WorkoutSectionSlides.

Furthermore, the view's attributes are only used while the the object is being constructed:

var View = Backbone.View = function(options) {
  this.cid = _.uniqueId('view');
  this._configure(options || {});
  this._ensureElement();
  this.initialize.apply(this, arguments);
  this.delegateEvents();
};

The _ensureElement call is the thing that uses attributes and you'll notice that it comes before initialize is called. That order combined with the prototype behavior is why your attribute shows up on the next instance of the view. The attributes is really meant for static properties, your this.$el.attr('tooltip', ...) solution is a good way to handle a dynamic attribute.

Upvotes: 5

Related Questions