How to set attributes in backbone models

2019-09-16 10:33发布

I'm trying to implement my app using backbone but I might have got something misunderstood.

I want to specify certain attributes(title etc.) while using certain default values. But the custom attributes are not set, why?

        var DataMapper = {
            Models: {},
            Collections: {},
            Views: {},
            Templates: {}
        };


        DataMapper.Views.OperatorView = Backbone.View.extend({
            el: "#op-panel",
            operators: [],
            events: {
                "click #concat-op-btn": "addConcatOp"
            },
            addConcatOp: function () {
                var concatOperator = new DataMapper.Models.OpContainerBox({title: "Concat", inputCount: 2, outputCount: 1});
                this.operators.push(concatOperator);
                concatOperator.drawContainer();
            }
        });


        DataMapper.Models.OpContainerBox = Backbone.Model.extend({
            title: "Operator",
            inputCount: 0,
            outputCount: 0,
            defaults: {
                x: 400,
                y: 40,
                leaves: [],
                height: 20,
                width: 120
            },
            drawContainer: function () {
                console.log(this.title); //outputs "Operator" not "Concat"
            }
        });
        new DataMapper.Views.OperatorView();

1条回答
我只想做你的唯一
2楼-- · 2019-09-16 11:18

Backbone model attributes are not the same as JavaScript object properties. Attributes are stored in the attributes property and you use get and set to work with them; properties are attached to this and directly accessed via this.property_name.

When you say this:

DataMapper.Models.OpContainerBox = Backbone.Model.extend({
    title: "Operator"
});

title will be a property, not an attribute. When you say this:

DataMapper.Models.OpContainerBox.new({
    title: 'Concat'
});

Backbone will set the title attribute to 'Concat'.

If you change your console.log call to:

console.log(this.title, this.get('title'));

you should see both 'Operator' and 'Concat' in the console.

All the defaults should go in the defaults property and if any of the defaults are mutable, then you should use a function for defaults to prevent accidental reference sharing:

DataMapper.Models.OpContainerBox = Backbone.Model.extend({
    defaults: function() {
        return {
            title: "Operator",
            inputCount: 0,
            outputCount: 0,
            x: 400,
            y: 40,
            leaves: [],
            height: 20,
            width: 120
        };
    },
    drawContainer: function () {
        console.log(this.get('title'));
    }
});

If you don't use a function for defaults then all OpContainerBox instances will share exactly the same defaults.leaves array through their prototype.

You'll also want to be sure to use get to access the attributes: this.get('title') not this.title.

This "reference sharing through the prototype" problem can also cause you problems with the operators array in your OperatorView so you might want to say this instead:

DataMapper.Views.OperatorView = Backbone.View.extend({
    el: "#op-panel",
    events: {
        "click #concat-op-btn": "addConcatOp"
    },
    initialize: function() {
        this.operators = [ ]; // <---- One distinct array per instance.
    },
    //...
});
查看更多
登录 后发表回答