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

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

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

다른 질문:

2) 모델에서 기본 객체를 제외하고 백본의 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);
  }
});

전체 설명 은 c3rin의 답변 @ https://stackoverflow.com/a/6364480/1072653 을 참조하십시오 .


답변

이 접근 방식을 사용합니다.

다음과 같은 백본 모델이있는 경우 :

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

다음을 사용하여 “ab”속성을 설정할 수 있습니다.

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

이제 모델에는 다음과 같은 속성이 있습니다.

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

“변경”이벤트가 발생했습니다.


답변

아직 아무도 생각하지 못한 하나의 솔루션이 있으며 사용할 것이 많습니다. 원하지 않는 타사 라이브러리를 사용하지 않는 한 실제로 중첩 된 속성을 직접 설정할 수 없습니다. 그러나 할 수있는 일은 원본 사전의 복제본을 만들고 중첩 된 속성을 설정 한 다음 전체 사전을 설정하는 것입니다. 케이크 조각.

//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


답변

@pagewil과 @Benno가 @Domenic의 솔루션과 동일한 문제를 겪었습니다. 내 대답은 대신 문제를 해결하는 Backbone.Model의 간단한 하위 클래스를 작성하는 것이 었습니다.

// 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}]
});

NestedModel이하는 일은 이러한 작업을 허용하는 것입니다 (이는 JSON 데이터를 통해 myModel이 설정 될 때 발생합니다).

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

초기화시 자동으로 모델 목록을 생성하는 것은 쉽지만이 솔루션은 저에게 충분했습니다.


답변

Domenic이 제안한 솔루션에는 몇 가지 단점이 있습니다. ‘변경’이벤트를 듣고 싶다고 가정 해 보겠습니다. 이 경우 ‘initialize’메소드가 실행되지 않고 속성에 대한 사용자 정의 값이 서버의 json 객체로 대체됩니다. 내 프로젝트에서 나는이 문제에 직면했습니다. 모델의 ‘set’메서드를 재정의하는 내 솔루션 :

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);
},