ember-data-change-tracker
Version:
Track changes and rollback object attributes and relationships. Ember data 2.5+
197 lines (172 loc) • 5.12 kB
JavaScript
import Ember from 'ember';
import Model from 'ember-data/model';
import Tracker from './tracker';
Model.reopen({
init(){
this._super(...arguments);
if (Tracker.isAutoSaveEnabled(this)) {
this.initTracking();
}
if (Tracker.isIsDirtyEnabled(this)) {
// this is experimental
Tracker.initializeDirtiness(this);
}
this.setupTrackerMetaData();
this.setupUnknownRelationshipLoadObservers();
},
/**
* Did an attribute/association change?
*
* @param {String} key the attribute/association name
* @param {Object} changed optional ember-data changedAttribute object
* @returns {Boolean} true if value changed
*/
didChange(key, changed, options) {
return Tracker.didChange(this, key, changed, options);
},
/**
* Did any attribute/association change?
*
* returns object with:
* {key: value} = {attribute: true}
*
* If the the attribute changed, it will be included in this object
*
* @returns {*}
*/
modelChanges() {
let changed = Ember.assign({}, this.changedAttributes());
let trackerInfo = Tracker.metaInfo(this);
for (let key in trackerInfo) {
if (!changed[key] && trackerInfo.hasOwnProperty(key)) {
if (this.didChange(key, changed)) {
changed[key] = true;
}
}
}
return changed;
},
/**
* Rollback all the changes on this model, for the keys you are
* tracking.
*
* NOTE: Be sure you understand what keys you are tracking.
* By default, tracker will save all keys, but if you set up
* a model to 'only' track a limited set of keys, then the rollback
* will only be limited to those keys
*
*/
rollback() {
const isNew = this.get('isNew');
this.rollbackAttributes();
if (isNew) { return; }
let trackerInfo = Tracker.metaInfo(this);
let rollbackData = Tracker.rollbackData(this, trackerInfo);
let normalized = Tracker.normalize(this, rollbackData);
this.store.push(normalized);
},
// alias for saveChanges method
startTrack() {
this.initTracking();
this.saveChanges();
},
// Ember Data DS.Model events
// http://api.emberjs.com/ember-data/3.10/classes/DS.Model/events
//
// Replaces deprecated Ember.Evented usage:
// https://github.com/emberjs/rfcs/blob/master/text/0329-deprecated-ember-evented-in-ember-data.md
// Related: https://github.com/emberjs/rfcs/pull/329
initTracking(){
this.didCreate = () => {
this.saveOnCreate();
}
this.didUpdate = () => {
this.saveOnUpdate();
}
this.didDelete = () => {
this.clearSavedAttributes();
}
this.ready = () => {
this.setupTrackerMetaData();
this.setupUnknownRelationshipLoadObservers();
},
Tracker.setupTracking(this);
},
/**
* Save the current state of the model
*
* NOTE: This is needed when manually pushing data
* to the store and ussing Ember < 2.10
*
* options like => {except: 'company'}
*
* @param {Object} options
*/
saveChanges(options) {
Tracker.setupTracking(this);
Tracker.saveChanges(this, options);
Tracker.triggerIsDirtyReset(this);
},
saveTrackerChanges(options) {
this.saveChanges(options);
},
/**
* Get value of the last known value tracker is saving for this key
*
* @param {String} key attribute/association name
* @returns {*}
*/
savedTrackerValue(key) {
return Tracker.lastValue(this, key);
},
// save state when model is loaded or created if using auto save
setupTrackerMetaData() {
if (Tracker.isIsDirtyEnabled(this)) {
// this is experimental
Tracker.initializeDirtiness(this);
}
if (Tracker.isAutoSaveEnabled(this)) {
this.saveChanges();
}
},
// watch for relationships loaded with data via links
setupUnknownRelationshipLoadObservers() {
this.eachRelationship((key) => {
this.addObserver(key, this, 'observeUnknownRelationshipLoaded');
});
},
// when model updates, update the tracked state if using auto save
saveOnUpdate() {
if (Tracker.isAutoSaveEnabled(this) || Tracker.isIsDirtyEnabled(this)) {
this.saveChanges();
}
},
// when model creates, update the tracked state if using auto save
saveOnCreate() {
if (Tracker.isAutoSaveEnabled(this) || Tracker.isIsDirtyEnabled(this)) {
this.saveChanges();
}
},
// There is no didReload callback on models, so have to override reload
reload() {
let promise = this._super(...arguments);
promise.then(() => {
if (Tracker.isAutoSaveEnabled(this)) {
this.saveChanges();
}
});
return promise;
},
// when model deletes, remove any tracked state
clearSavedAttributes() {
Tracker.clear(this);
},
observeUnknownRelationshipLoaded(sender, key/*, value, rev*/) {
if (Tracker.trackingIsSetup(this) && Tracker.isTracking(this, key)) {
let saved = Tracker.saveLoadedRelationship(this, key);
if (saved) {
this.removeObserver(key, this, 'observeUnknownRelationshipLoaded');
}
}
}
});