program tip

Backbone.js는 중첩 된 객체 속성을 가져오고 설정합니다.

radiobox 2020. 8. 11. 08:16
반응형

Backbone.js는 중첩 된 객체 속성을 가져오고 설정합니다.


Backbone.js의 getset 함수 에 대한 간단한 질문이 있습니다.

1) 아래 코드를 사용하여 obj1.myAttribute1을 직접 '가져 오기'또는 '설정'할 수 있습니까?

다른 질문:

2) 모델에서 기본 개체를 제외하고, Backbone의 get 및 set 메서드를 통해 액세스 할 수 있도록 모델의 다른 속성을 어디에서 선언해야합니까?

var MyModel = Backbone.Model.extend({
    defaults: {
        obj1 : {
            "myAttribute1" : false,
            "myAttribute2" : true,
        }
    }
})

var MyView = Backbone.View.extend({
    myFunc: function(){
        console.log(this.model.get("obj1"));
        //returns the obj1 object
        //but how do I get obj1.myAttribute1 directly so that it returns false?
    }
});

나는 내가 할 수 있다는 것을 안다.

this.model.get("obj1").myAttribute1;

하지만 그게 좋은 습관인가요?


하지만 this.model.get("obj1").myAttribute1잘은 다음 세트에 대한 물건의 동일한 유형을 유혹 할 수 있기 때문에, 그것은, 즉 약간의 문제입니다

this.model.get("obj1").myAttribute1 = true;

그러나 이렇게하면 myAttribute1변경 이벤트 또는 유효성 검사와 같은에 대한 백본 모델의 이점을 얻을 수 없습니다 .

더 나은 해결책은 모델에 POJSO ( "일반 JavaScript 객체")를 중첩하지 않고 대신 사용자 정의 모델 클래스를 중첩하는 것입니다. 따라서 다음과 같이 보일 것입니다.

var Obj = Backbone.Model.extend({
    defaults: {
        myAttribute1: false,
        myAttribute2: true
    }
});

var MyModel = Backbone.Model.extend({
    initialize: function () {
        this.set("obj1", new Obj());
    }
});

그러면 액세스 코드는

var x = this.model.get("obj1").get("myAttribute1");

그러나 더 중요한 것은 설정 코드가

this.model.get("obj1").set({ myAttribute1: true });

적절한 변경 이벤트 등이 발생합니다. 작업 예 : http://jsfiddle.net/g3U7j/


이를 위해 backbone-deep-model만들었습니다. Backbone.Model 대신 Backbone.DeepModel을 확장 한 다음 경로를 사용하여 중첩 된 모델 속성을 가져 오거나 설정할 수 있습니다. 변경 이벤트도 유지합니다.

model.bind('change:user.name.first', function(){...});
model.set({'user.name.first': 'Eric'});
model.get('user.name.first'); //Eric

Domenic의 솔루션은 작동하지만 각각의 새로운 MyModel은 동일한 Obj 인스턴스를 가리 킵니다. 이를 방지하기 위해 MyModel은 다음과 같아야합니다.

var MyModel = Backbone.Model.extend({
  initialize: function() {
     myDefaults = {
       obj1: new Obj()
     } 
     this.set(myDefaults);
  }
});

See c3rin's answer @ https://stackoverflow.com/a/6364480/1072653 for a full explanation.


I use this approach.

If you have a Backbone model like this:

var nestedAttrModel = new Backbone.Model({
    a: {b: 1, c: 2}
});

You can set the attribute "a.b" with:

var _a = _.omit(nestedAttrModel.get('a')); // from underscore.js
_a.b = 3;
nestedAttrModel.set('a', _a);

Now your model will have attributes like:

{a: {b: 3, c: 2}}

with the "change" event fired.


There is one solution nobody thought of yet which is lots to use. You indeed can't set nested attributes directly, unless you use a third party library which you probably don't want. However what you can do is make a clone of the original dictionary, set the nested property there and than set that whole dictionary. Piece of cake.

//How model.obj1 looks like
obj1: {
    myAttribute1: false,
    myAttribute2: true,
    anotherNestedDict: {
        myAttribute3: false
    }
}

//Make a clone of it
var cloneOfObject1 = JSON.parse(JSON.stringify(this.model.get('obj1')));

//Let's day we want to change myAttribute1 to false and myAttribute3 to true
cloneOfObject1.myAttribute2 = false;
cloneOfObject1.anotherNestedDict.myAttribute3 = true;

//And now we set the whole dictionary
this.model.set('obj1', cloneOfObject1);

//Job done, happy birthday

I had the same problem @pagewil and @Benno had with @Domenic's solution. My answer was to instead write a simple sub-class of Backbone.Model that fixes the problem.

// Special model implementation that allows you to easily nest Backbone models as properties.
Backbone.NestedModel = Backbone.Model.extend({
    // Define Backbone models that are present in properties
    // Expected Format:
    // [{key: 'courses', model: Course}]
    models: [],

    set: function(key, value, options) {
        var attrs, attr, val;

        if (_.isObject(key) || key == null) {
            attrs = key;
            options = value;
        } else {
            attrs = {};
            attrs[key] = value;
        }

        _.each(this.models, function(item){
            if (_.isObject(attrs[item.key])) {
                attrs[item.key] = new item.model(attrs[item.key]);
            }
        },this);

        return Backbone.Model.prototype.set.call(this, attrs, options);
    }
});

var Obj = Backbone.Model.extend({
    defaults: {
        myAttribute1: false,
        myAttribute2: true
    }
});

var MyModel = Backbone.NestedModel.extend({
    defaults: {
        obj1: new Obj()
    },

    models: [{key: 'obj1', model: Obj}]
});

What NestedModel does for you is allow these to work (which is what happens when myModel gets set via JSON data):

var myModel = new MyModel();
myModel.set({ obj1: { myAttribute1: 'abc', myAttribute2: 'xyz' } });
myModel.set('obj1', { myAttribute1: 123, myAttribute2: 456 });

It would be easy to generate the models list automatically in initialize, but this solution was good enough for me.


Solution proposed by Domenic has some drawbacks. Say you want to listen to 'change' event. In that case 'initialize' method will not be fired and your custom value for attribute will be replaced with json object from server. In my project I faced with this problem. My solution to override 'set' method of Model:

set: function(key, val, options) {
    if (typeof key === 'object') {
        var attrs = key;
        attrs.content = new module.BaseItem(attrs.content || {});
        attrs.children = new module.MenuItems(attrs.children || []);
    }

    return Backbone.Model.prototype.set.call(this, key, val, options);
}, 

While in some cases using Backbone models instead of nested Object attributes makes sense as Domenic mentioned, in simpler cases you could create a setter function in the model:

var MyModel = Backbone.Model.extend({
    defaults: {
        obj1 : {
            "myAttribute1" : false,
            "myAttribute2" : true,
        }
    },
    setObj1Attribute: function(name, value) {
        var obj1 = this.get('obj1');
        obj1[name] = value;
        this.set('obj1', obj1);
    }
})

If you interact with backend, which requires object with nesting structure. But with backbone more easy to work with linear structure.

backbone.linear can help you.

참고URL : https://stackoverflow.com/questions/6351271/backbone-js-get-and-set-nested-object-attribute

반응형