wake-up-neo.com

Backbone.js holt das geschachtelte Objektattribut und setzt es

Ich habe eine einfache Frage zu den Funktionen von Backbone.js get und set .

1) Wie kann ich obj1.myAttribute1 mit dem folgenden Code direkt "abrufen" oder "einstellen"?

Eine andere Frage:

2) Wo kann/sollte ich im Model neben dem Objekt defaults die anderen Attribute meines Modells angeben, sodass sie über die get- und set-Methoden von Backbone aufgerufen werden können?

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

Ich weiß ich kann:

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

aber ist das eine gute Praxis? 

105
fortuneRice

Während this.model.get("obj1").myAttribute1 in Ordnung ist, ist es ein bisschen problematisch, weil Sie dann versucht sein könnten, die gleiche Art von Dingen für ein Set auszuführen, d. H.

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

Wenn Sie dies tun, erhalten Sie jedoch nicht die Vorteile von Backbone-Modellen für myAttribute1 wie Änderungsereignisse oder Validierung.

Eine bessere Lösung wäre, POJSOs ("einfache alte JavaScript-Objekte") niemals in Ihren Modellen zu verschachteln, sondern benutzerdefinierte Modellklassen zu verschachteln. So würde es ungefähr so ​​aussehen:

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

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

Dann wäre der Zugangscode

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

aber noch wichtiger wäre der Einstellungscode 

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

die entsprechende Änderungsereignisse und dergleichen abfeuern. Arbeitsbeispiel hier: http://jsfiddle.net/g3U7j/

144
Domenic

Ich habe backbone-deep-model dafür erstellt - erweitern Sie einfach Backbone.DeepModel anstelle von Backbone.Model, und Sie können dann Pfade verwenden, um verschachtelte Modellattribute abzurufen/festzulegen. Es unterhält auch Änderungsereignisse.

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

Die Lösung von Domenic wird funktionieren, jedoch wird jedes neue MyModel auf dieselbe Instanz von Obj verweisen. Um dies zu vermeiden, sollte MyModel folgendermaßen aussehen: 

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

Eine vollständige Erklärung finden Sie in der Antwort von c3rin @ https://stackoverflow.com/a/6364480/1072653 .

16
Rusty

Ich benutze diesen Ansatz.

Wenn Sie ein Backbone-Modell wie dieses haben:

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

Sie können das Attribut "a.b" festlegen mit:

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

Jetzt hat Ihr Modell Attribute wie:

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

mit dem "change" -Ereignis ausgelöst.

Es gibt eine Lösung, an die noch niemand gedacht hat, die viel zu gebrauchen ist. Sie können verschachtelte Attribute nicht direkt festlegen, es sei denn, Sie verwenden eine Drittanbieter-Bibliothek, die Sie wahrscheinlich nicht möchten. Sie können jedoch einen Klon des ursprünglichen Wörterbuchs erstellen, die verschachtelte Eigenschaft dort festlegen und dann das gesamte Wörterbuch festlegen. Stück Kuchen.

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

Ich hatte das gleiche Problem @pagewil und @Benno hatte mit der Lösung von @ Domenic. Meine Antwort war, stattdessen eine einfache Unterklasse von Backbone.Model zu schreiben, die das Problem behebt.

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

Was NestedModel für Sie tut, ist, dass diese funktionieren.

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

Es wäre leicht, die Modellliste automatisch beim Initialisieren zu generieren, aber diese Lösung war für mich gut genug.

2
Cory Gagliardi

Die von Domenic vorgeschlagene Lösung weist einige Nachteile auf. Angenommen, Sie möchten das Änderungsereignis anhören. In diesem Fall wird die Initialisierungsmethode nicht ausgelöst und Ihr benutzerdefinierter Attributwert wird durch das Json-Objekt vom Server ersetzt. In meinem Projekt bin ich mit diesem Problem konfrontiert. Meine Lösung zum Überschreiben der Set-Methode von 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);
}, 
2
yuliskov

Wenn Sie mit dem Backend interagieren, ist ein Objekt mit der Verschachtelungsstruktur erforderlich. Mit Backbone ist es jedoch einfacher, mit linearer Struktur zu arbeiten.

backbone.linear kann dir helfen.

0
darky

Während in einigen Fällen die Verwendung von Backbone-Modellen anstelle von verschachtelten Objektattributen sinnvoll ist, wie Domenic erwähnt, können Sie in einfacheren Fällen eine Setterfunktion im Modell erstellen:

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