2013-02-04 9 views
8

Ich habe zwei Modelle mit Eltern-Kind-Beziehung: Ausbildung und Übung:Wie Rollback Beziehung Änderungen in EmberData

App.Training = DS.Model.extend({ 
    exercises: DS.hasMany('App.Exercise') 
}) 

App.Exercise = DS.Model.extend({ 
    training: DS.belongsTo('App.Training') 
}) 

Ich mag eine Seite haben, wo ein Training mit all ihren verwandten Übungen angezeigt. Wenn der Benutzer die Taste Edit drückt, wird die Seite mit der Möglichkeit bearbeitet, neue Übungen hinzuzufügen. Ich möchte auch eine Cancel Schaltfläche haben, die alle vorgenommenen Änderungen verwirft.

Hier ist mein Controller:

App.TrainingsShowController = Em.ObjectController.extend({ 
    editing: false, 

    edit: function() { 
    this.set('editing', true); 
    transaction = this.get('store').transaction(); 
    transaction.add(this.get('model')); 
    this.get('model.exercises').forEach(function(x){ 
     transaction.add(x); 
    }); 
    }, 

    cancel: function() { 
    this.set('editing', false); 
    this.get('model.transaction').rollback(); 
    }, 

    save: function() { 
    this.set('editing', false); 
    this.get('model.transaction').commit(); 
    }, 

    addExercise: function() { 
    this.get('model.exercises').createRecord({}); 
    } 
}) 

Es in der Steuerung vier Event-Handler sind:

  1. edit: Der Benutzer kann die Edit Taste gedrückt: eine Transaktion erstellt wird, wird die Seite setzen in "Bearbeiten" -Modus.
  2. cancel: Der Benutzer drückte die Cancel Schaltfläche: Die Transaktion wird zurückgesetzt und zurück in den "normalen" Modus.
  3. save: Der Benutzer drückte die Save Schaltfläche: Transaktion wird festgeschrieben und zurück in den "normalen" Modus.
  4. addExercise: Der Benutzer drückte die Add exercise Schaltfläche: eine neue Übung wird erstellt (in derselben Transaktion) und zu den Schulungen hinzugefügt.

Die Rollback-Funktionalität funktioniert gut für neu erstellte Datensätze mit Ausnahme: wenn ich die Edit Taste drücken, eine neue Übung hinzufügen, und drücken Sie die Taste Cancel, die neu erstellten Trainingsaufenthalt auf der Seite.

Was ist der beste Weg, um den verworfenen Kind Datensatz loszuwerden?

UPDATE:

ich ein jsFiddle erstellt haben Problem zu reproduzieren, aber es funktionierte. Im Gegensatz zu meiner Anwendung hier verwendete ich DS.FixtureAdapter: http://jsfiddle.net/tothda/LaXLG/13/

Dann habe ich eine andere erstellt DS.RESTAdapter verwenden und das Problem aufgetaucht: http://jsfiddle.net/tothda/qwZc4/5/

In der Geige versuchen: Bearbeiten, neue hinzufügen und dann auf Zurücksetzen.

Ich fand heraus, dass im Falle des RESTAdapter, wenn ich einen neuen Kind-Datensatz zu einer hasMany Beziehung hinzufügen, der Eltern-Datensatz nicht schmutzig werden. Was scheint in Ordnung, aber wenn ich die Transaktion Rollback, bleibt der neu erstellte Kind-Datensatz in der ManyArray des Elternteils.

Ich weiß immer noch nicht, was ist der beste Weg, um mit der Situation umzugehen.

Antwort

1

Das ist nicht schön, aber man kann es manuell rückgängig zu machen erzwingen, indem Sie den übergeordneten Datensatz zu beschmutzen:

parent.send('becomeDirty'); 
parent.rollback(); 
parent.get('children.length'); // => 0 
0

@tothda und andere Leser zu folgen. Ab Ember Data : 1.0.0-beta.10+canary.7db210f29a ist das übergeordnete Element immer noch nicht dafür ausgelegt, parentTraining.isDirty() einen Wert von wahr zu machen, wenn ein Kind zurückgesetzt wird.Ember Daten tun einen übergeordneten Datensatz betrachten dirty zu sein, wenn ein Attribut geändert wird, aber nicht wenn ein DS.hasMany Array Änderungen hat (this allows save() zu arbeiten, so dass Sie Änderungen aktualisiert können die Eltern Attribut auf dem Server).

Der Weg, um dies für den Fall genannt, in dem Sie ein rollback() auf ein neu geschaffenes Kind tun wollen, ist die .rollback() mit einem .deleteRecord() auf der untergeordneten Datensatz Sie verwerfen wollen zu ersetzen. Ember Data erkennt dann automatisch, dass es aus dem DS.hasMany Array entfernt wird, und Sie können sich auf die Rückseite klopfen, um einen Rollback zu machen!

11

Ein richtiger Dirty Check und Rollback für hasMany und anglesTo Beziehungen fehlen sehr in Ember Data. Die Art und Weise, wie es sich derzeit verhält, wird oft als Fehler gemeldet. Dies ist ein großer Schmerz Punkt für viele Entwickler und es gibt eine anhaltende Diskussion darüber, wie dies hier zu beheben:

https://github.com/emberjs/rfcs/pull/21

Bis es eine richtige Lösung vorhanden ist, können Sie dieses Problem umgehen können, indem Sie Folgendes verwenden Ansatz.

Zuerst möchten Sie DS.Model erneut öffnen und erweitern. Wenn Sie globale Variablen verwenden, können Sie dies einfach (z. B. DS.Model.reopen ({})) an eine beliebige Stelle setzen. Wenn Sie jedoch Ember CLI verwenden, erstellen Sie am besten einen Initialisierer (z. B. ember g initialiser model):

Der obige Code speichert im Wesentlichen die ursprünglichen Beziehungen beim Laden oder Aktualisieren, so dass sie später für Rollback und Dirty Checking verwendet werden können.

model.rollback() sollte nun alles zurücksetzen, einschließlich hasMany und anglesoTo-Beziehungen. Wir haben die Überprüfung von "isDirty" jedoch noch nicht vollständig durchgeführt. Um dies zu erreichen, müssen wir isDirty in der konkreten Implementierung eines Modells überschreiben. Der Grund, warum wir dies hier tun müssen und wir es nicht generisch in DS.Model tun können, liegt daran, dass DS.Model nicht weiß, auf welche Eigenschaft sich Änderungen beziehen sollen. Hier ist ein Beispiel mit Ember CLI. Der gleiche Ansatz würde mit Globals verwendet werden, mit der Ausnahme, dass Sie diese Klasse wie App.Book etwas zuordnen würden:

import DS from 'ember-data'; 

var Book = DS.Model.extend({ 

    publisher: DS.belongsTo('publisher'), 

    authors: DS.hasMany('author'), 

    isDirty: function() { 
     return this.isDeepDirty(); 
    }.property('currentState', 'publisher', 'authors.[]', '[email protected]').readOnly() 

}); 

export default Book; 

Für die abhängigen Argumente von isDirty, stellen Sie sicher, dass alle belongsTo Beziehungen aufzunehmen und auch ‚Array . [] 'und' array. @ each.isDirty 'für jede hasMany-Beziehung. Jetzt sollte isDirty wie erwartet funktionieren.

+2

Dies ist eine nette Idee, aber es scheint, wie jetzt meine Anwendung alle Asynchron relationsships sofort wird geladen (was eine Weile dauert), anstatt zu warten, bis die tatsächlich benutzt werden? Korrigiere mich, wenn ich falsch liege. – justastefan

+0

@justastefan, gute Beobachtung. saveOriginalRelations lädt wahrscheinlich alle asynchronen Beziehungen. Wenn Sie asynchrone Beziehungen haben, ist es schwieriger, diese Technik zu implementieren. Sie müssen die ursprünglichen Beziehungen erst speichern, nachdem sie geladen wurden, und das Zurücksetzen nicht geladener Beziehungen ignorieren. –

+0

Während der Aktualisierung auf ember-data 1.13.7 habe ich [versucht zu aktualisieren] (https://gist.github.com/masciugo/0e2eee85a42b13fac9e3) diese Problemumgehung zu, aber keinen Erfolg. Kannst du mir bitte helfen? – masciugo