Как вручную установить состояние объекта для очистки (сохранения) с использованием ember-data

Объяснение:

Я использую ember-data для моего проекта, и у меня есть вопрос, который вращается вокруг возможности загрязнения объекта, а затем установки его состояния для очистки снова специально - без фиксации изменений. Сценарий таков:

Скажем, я получил объект через banana = App.Fruit.find('banana'); и в нем есть описание "Желтые фрукты!". Используя длительный опрос XHR (или WebSockets), я могу получить обновленную версию объекта, поскольку другой пользователь изменил описание на "Вкусный желтый фрукт!" в любой момент времени после того, как я извлек исходный объект.

Затем я хотел бы обновить объект, чтобы отразить вновь полученные данные. Для этого я пробовал разные подходы:

  • Я пробовал звонить App.Store.load(App.Fruit, new_data);, Во-первых, этот подход не работает, а во-вторых, это не совсем то, чего я хочу. Я мог бы внести незафиксированные изменения в объект сам, и в этом случае было бы нежелательно просто отбрасывать их (предполагая, что load() звонок переписал бы их).

  • Я пробовал перебирать новые данные, вызывая .set() - вот так: banana.set('description', new_data.description); - для обновления свойств объекта новыми данными (где применимо = не загрязнено). Это работает, но оставляет объект в грязном состоянии.

Для того, чтобы сделать объект чистым / обновленным снова - и не заставляйте адаптер фиксировать изменения! - Я посмотрел на состояния, через которые проходит объект. Это (как минимум):

  • Шаг 1: изначально объект находится в rootState.loaded.saved государство.
  • Шаг 2: Звонок .set() на имущество толкает его к rootState.loaded.updated.uncommitted государство.
  • Шаг 3: Звонок App.store.commit(); возвращает объект в rootState.loaded.saved государство.

Поэтому я попытался вручную установить состояние объекта saved после шага 2 вроде так: banana.get('stateManager').goToState('saved');,

Тем не менее, это не работает. В следующий раз, когда хранилище будет выполнено по любой другой причине, этот маневр выдаст inFlightDirtyReasons - неопределенная ошибка.

Вопрос:

Мой вопрос: как я могу вручную изменить состояние загрязненного объекта, чтобы снова очистить (сохранить)?

12 ответов

Решение

Если посмотреть на данные ember, то в незафиксированном состоянии есть событие "gotClean", которое, следовательно, устанавливает запись как загруженный.

Это должно сделать свое дело

record.get('stateManager').send('becameClean');  

Решение для Ember Data 1.0.0-beta.7:

// changing to loaded.updated.inFlight, which has "didCommit" 
record.send('willCommit'); 
// clear array of changed (dirty) model attributes
record.set('_attributes', {});
// changing to loaded.saved (hooks didCommit event in "inFlight" state)
record.send('didCommit');

Я искал исходный код Ember-data и обнаружил, что в состоянии load.saved есть функция настройки, которая проверяет, является ли модель чистой, перед установкой состояния "сохранено". Если он не является чистым, то он отклоняет запрос на изменение состояния и возвращает к нагруженному. Updated.uncommitted.

Поэтому вы должны очистить массив model._attributes, в котором хранятся имена атрибутов, а Ember позволит вам изменять состояние вручную.

Я знаю, что это не очень хорошее решение, потому что необходимо установить частную собственность модели, но я пока не нашел других решений.

Решение для Ember Data 2.6.1

record.send('pushedData');

установить грязную запись как загруженную и сохраненную

https://github.com/emberjs/data/blob/fec260a38c3f7227ffe17a3af09973ce2718acca/addon/-private/system/model/states.js#L250

Это обновление для решения @Kamil-j.

Для Ember Data 2.0, которую я сейчас использую, мне нужно сделать следующее:

record._internalModel.send('willCommit'); 
record._internalModel._attributes = {};
record._internalModel.send('didCommit');

По состоянию на ember-data1.0.0-beta.12:

record.transitionTo('loaded.saved');

Кажется, что record.get('stateManager') больше не требуется.

По состоянию на 1.0.0.rc6.2....

Это переместит модель в состояние модели, которая была сохранена.

record.get('stateManager').transitionTo('loaded.saved') 

Это переместит модель в состояние новой модели, которая не была зафиксирована. Подумайте, новая грязная модель.

record.get('stateManager').transitionTo('loaded.created.uncommitted')

Это переместит модель в состояние старой модели, которая была обновлена, представьте себе старую грязную модель:

record.get('stateManager').transitionTo('loaded.updated')

Вот что работает для Ember Data 1.0.0-beta.10:

record.set('currentState.stateName', 'root.loaded.saved');
record.adapterWillCommit();
record.adapterDidCommit();
record.set('currentState.isDirty', false);

Не уверен, что все эти строки требуются, но просто следуют тому, что другие сделали до этого.

Эмбер 2.9.1

record.set('currentState.isDirty', false);

Проверено на Ember Data 2.9

Действие pressedData - это то, что нужно, но кроме этого необходимо также сбросить "originalValues".

Ember.assign(record.data, record._internalModel._attributes);
Ember.assign(record._internalModel._data, record._internalModel._attributes);
record.send('pushedData');

Проверено на Ember Data 3.8.0

Просто обновление ответа Мартина Малинды:

// Clear changed attributes list 
record._internalModel._recordData._attributes = {};

// Trigger transition to 'loaded.saved' state
record.send('pushedData');

В моем случае мне также нужно было переопределить сериализатор normalize метод.

Еще один метод, который работал для меня при использовании Ember Data 1.0.0-beta.18:

record.rollback()

Это полностью изменило грязные атрибуты и вернуло запись в чистое состояние.

Похоже, это могло быть с тех пор устарело в пользу record.rollbackAttributes: http://emberjs.com/api/data/classes/DS.Model.html

Я работаю с данными Ember 1.13, поэтому я использовал следующее решение (которое, похоже, представляет собой сочетание между предоставленным @Martin Malinda и другим @Serge):

// Ensure you have the changes inside the record
Object.assign(record.data, record._internalModel._attributes);
Object.assign(record._internalModel._data,record._internalModel._attributes);

// Using the DS.State you can first simulate the record is going to be saved
record.get('_internalModel').send('willCommit');

// Cleaning the prevous dirty attributes
record.get('_internalModel')._attributes = {};

// Mark the record as saved (root.loaded.created.uncommitted) even if it isn't for real
record.get('_internalModel').send('didCommit');

Таким образом, если мы будем называть еще rollbackAttributes() в этой записи, если у нас будут некоторые грязные атрибуты, запись будет сброшена в это последнее состояние (вместо того, чтобы иметь исходные свойства), которое было именно тем, что я искал в моем случае использования.

Если у нас не будет грязных атрибутов, ничего не изменится, и мы сохраним последние атрибуты, установленные с помощью этого кода, без их отката к исходным. Надеюсь, поможет.

Похоже, что в более новых версиях все метионированные здесь сломались.

Это сработало для меня с ember-data 1.0.0.beta4:

record.adapterWillCommit();
record.adapterDidCommit();
Другие вопросы по тегам