Как вручную установить состояние объекта для очистки (сохранения) с использованием 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');
установить грязную запись как загруженную и сохраненную
Это обновление для решения @Kamil-j.
Для Ember Data 2.0, которую я сейчас использую, мне нужно сделать следующее:
record._internalModel.send('willCommit');
record._internalModel._attributes = {};
record._internalModel.send('didCommit');
По состоянию на ember-data
1.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);
Не уверен, что все эти строки требуются, но просто следуют тому, что другие сделали до этого.
Проверено на 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();