@cityads/ember-data-change-tracker 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +15 -0
- package/LICENSE.md +9 -0
- package/README.md +308 -0
- package/addon/index.js +4 -0
- package/addon/initializer.js +4 -0
- package/addon/mixins/keep-only-changed.js +26 -0
- package/addon/model-ext.js +212 -0
- package/addon/tracker.js +570 -0
- package/addon/transforms/json.js +20 -0
- package/addon/transforms/object.js +20 -0
- package/addon/utilities.js +92 -0
- package/app/initializers/ember-data-change-tracker.js +7 -0
- package/app/mixins/change-serializer.js +1 -0
- package/app/transforms/json.js +1 -0
- package/app/transforms/object.js +1 -0
- package/config/environment.js +6 -0
- package/index.js +6 -0
- package/package.json +65 -0
package/.eslintrc.js
ADDED
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# ember-data-change-tracker
|
|
2
|
+
|
|
3
|
+
[](http://badge.fury.io/js/@cityads%2Fember-data-change-tracker)
|
|
4
|
+
|
|
5
|
+
**New**
|
|
6
|
+
- Experimental feature
|
|
7
|
+
- isDirty, hasDirtyRelations computed properties
|
|
8
|
+
- Set up in [configuration](https://github.com/danielspaniel/ember-data-change-tracker#configuration) as { enableIsDirty: true }
|
|
9
|
+
- It is experimental and a has one crippling defect, it can not track object type
|
|
10
|
+
attributes. But if you don't have object types it works fine.
|
|
11
|
+
|
|
12
|
+
This addon aims to fill in the gaps in the change tracking / rollback that ember data does now.
|
|
13
|
+
|
|
14
|
+
- Currently ember-data
|
|
15
|
+
- tracks changes for numbers/strings/date/boolean attributes
|
|
16
|
+
- has a ```changedAttributes()``` method to see what changed => [ last, current ]
|
|
17
|
+
- has a ```rollbackAttributes()``` method to rollback attributes
|
|
18
|
+
- has a ```hasDirtyAttributes``` computed property
|
|
19
|
+
|
|
20
|
+
- This addon:
|
|
21
|
+
- tracks modifications in attributes that are object/json/custom type
|
|
22
|
+
- tracks replacement of belongsTo associations
|
|
23
|
+
- tracks replacement/changes in hasMany associations
|
|
24
|
+
- adds a ```modelChanges()``` method to DS.Model
|
|
25
|
+
- adds a ```rollback()``` method to DS.Model
|
|
26
|
+
- adds a ```isDirty``` computed property to DS.Model ( only if enabled in configuration )
|
|
27
|
+
- adds a ```hasDirtyRelations``` computed property to DS.Model ( only if enabled in configuration )
|
|
28
|
+
- Only works with
|
|
29
|
+
- ember-data versions 2.7+ ( if you have polymphic relationships )
|
|
30
|
+
- ember-data versions 2.5+ ( if you don't )
|
|
31
|
+
- Can be used in two modes
|
|
32
|
+
- auto track mode
|
|
33
|
+
- manual track mode ( the default )
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
* `ember install ember-data-change-tracker`
|
|
38
|
+
|
|
39
|
+
## Why?
|
|
40
|
+
|
|
41
|
+
Say there is a user model like this:
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
export default Model.extend({
|
|
45
|
+
name: attr('string'), // ember-data tracks this already
|
|
46
|
+
info: attr('object'), // ember-data does not track modifications
|
|
47
|
+
json: attr(), // ember-data does not track modifications if this is object
|
|
48
|
+
company: belongsTo('company', { async: false, polymorphic: true }), // ember-data does not track replacement
|
|
49
|
+
profile: belongsTo('profile', { async: true }), // ember-data does not track replacement
|
|
50
|
+
projects: hasMany('project', { async: false }), // ember-data does not track additions/deletions
|
|
51
|
+
pets: hasMany('pet', { async: true, polymorphic: true }) // ember-data does not track additions/deletions
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
You can not currently rollback the info, json if they are modified
|
|
56
|
+
or company, profile, projects and pets if they change.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### model changes
|
|
60
|
+
|
|
61
|
+
- The method ```modelChanges()``` is added to model
|
|
62
|
+
- Shows you any changes in an object attribute type
|
|
63
|
+
- whether modified or replacing the value
|
|
64
|
+
- attr() will default to 'object' type
|
|
65
|
+
- works with any custom type you have created
|
|
66
|
+
- Shows when you replace a belongsTo association
|
|
67
|
+
- Shows when you add to a hasMany association
|
|
68
|
+
- Shows when you delete from a hasMany association
|
|
69
|
+
- Merges ember-data `changeAttribute()` information into one unified change object
|
|
70
|
+
- Unlike ember-data no last and current value is shown, just the boolean => true
|
|
71
|
+
- Though you will see [last value, current value] for the attributes that ember-data tracks
|
|
72
|
+
|
|
73
|
+
Example: ( remove from a hasMany )
|
|
74
|
+
```javascript
|
|
75
|
+
user.get('projects').removeObject(firstProject); // remove project1
|
|
76
|
+
user.modelChanges() //=> {projects: true }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
### Rollback
|
|
81
|
+
|
|
82
|
+
- The method ```rollback()``` is added to model
|
|
83
|
+
- If you're not using auto track you have to call ```startTrack()``` before editing
|
|
84
|
+
- Performace wise, it's way faster than you think it should be.
|
|
85
|
+
- Tested on model with hundreds of items in a hasMany association.
|
|
86
|
+
- Though you might want to think twice when tracking one with thousands
|
|
87
|
+
|
|
88
|
+
Usage:
|
|
89
|
+
|
|
90
|
+
- make and makeList are from [ember-data-factory-guy](https://github.com/danielspaniel/ember-data-factory-guy).
|
|
91
|
+
- they create and push models ( based on factories ) into the ember-data store
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
let info = {foo: 1};
|
|
95
|
+
let projects = makeList('project', 2);
|
|
96
|
+
let [project1] = projects;
|
|
97
|
+
let pets = makeList('cat', 4);
|
|
98
|
+
let [cat, cat2] = pets;
|
|
99
|
+
let bigCompany = make('big-company');
|
|
100
|
+
let smallCompany = make('small-company');
|
|
101
|
+
|
|
102
|
+
let user = make('user', { profile: profile1, company: bigCompany, pets, projects });
|
|
103
|
+
|
|
104
|
+
// manual tracking model means you have to explicitly call => startTrack
|
|
105
|
+
// to save the current state of things before you edit
|
|
106
|
+
user.startTrack();
|
|
107
|
+
|
|
108
|
+
// edit things
|
|
109
|
+
user.setProperties({
|
|
110
|
+
'info.foo': 3,
|
|
111
|
+
company: smallCompany,
|
|
112
|
+
profile: profile2,
|
|
113
|
+
projects: [project1],
|
|
114
|
+
pets: [cat1, cat2]
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
user.rollback();
|
|
118
|
+
|
|
119
|
+
// it's all back to the way it was
|
|
120
|
+
user.get('info') //=> {foo: 1}
|
|
121
|
+
user.get('profile') //=> profile1
|
|
122
|
+
user.get('company') //=> bigCompany
|
|
123
|
+
user.get('projects') //=> first 2 projects
|
|
124
|
+
user.get('pets') //=> back to the same 4 pets
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### isDirty, hasDirtyRelations
|
|
129
|
+
- Computed properties to check if the model has changed
|
|
130
|
+
- Not enabled by default
|
|
131
|
+
- Need to set enableIsDirty ( true ) on model or global [configuration](https://github.com/danielspaniel/ember-data-change-tracker#configuration)
|
|
132
|
+
- The only attributes that can NOT be tracked with isDirty are object/array
|
|
133
|
+
attributes
|
|
134
|
+
|
|
135
|
+
Usage:
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
|
|
139
|
+
let info = {foo: 1};
|
|
140
|
+
let pets = makeList('cat', 4);
|
|
141
|
+
let [cat, cat2] = pets;
|
|
142
|
+
let bigCompany = make('big-company');
|
|
143
|
+
let smallCompany = make('small-company');
|
|
144
|
+
|
|
145
|
+
let user = make('user', { company: bigCompany, pets });
|
|
146
|
+
|
|
147
|
+
user.startTrack();
|
|
148
|
+
|
|
149
|
+
// edit things
|
|
150
|
+
user.set('name', "new name");
|
|
151
|
+
user.get('isDirty'); //=> true
|
|
152
|
+
|
|
153
|
+
user.rollback();
|
|
154
|
+
user.get('isDirty'); //=> false
|
|
155
|
+
|
|
156
|
+
user.set('company', smallCompany);
|
|
157
|
+
user.get('hasDirtyRelations'); //=> true
|
|
158
|
+
user.get('isDirty'); //=> true
|
|
159
|
+
|
|
160
|
+
user.rollback();
|
|
161
|
+
user.get('isDirty'); //=> false
|
|
162
|
+
|
|
163
|
+
user.set('pets', [cat, cat2]);
|
|
164
|
+
user.get('hasDirtyRelations'); //=> true
|
|
165
|
+
user.get('isDirty'); //=> true
|
|
166
|
+
|
|
167
|
+
user.rollback();
|
|
168
|
+
user.get('isDirty'); //=> false
|
|
169
|
+
|
|
170
|
+
// things that don't work
|
|
171
|
+
user.set('info.foo', 3);
|
|
172
|
+
user.get('isDirty'); //=> false ( object/array attributes don't work for computed isDirty )
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Configuration
|
|
177
|
+
|
|
178
|
+
- Global configuration
|
|
179
|
+
- By default the global settings are:
|
|
180
|
+
- { **trackHasMany**: *true*, **auto**: *false*, **enableIsDirty**: *false* }
|
|
181
|
+
- Essentially this says, track everything in the model but only when I tell you
|
|
182
|
+
- Since this is manual mode you probably want to track everything
|
|
183
|
+
since you are focused on one edit at a time, hence trackHasMany is on
|
|
184
|
+
- The options available are:
|
|
185
|
+
- **trackHasMany** : should hasMany associations be tracked? ( _true_ is default )
|
|
186
|
+
- this is just a shortcut to exclude all the hasMany relations
|
|
187
|
+
- **auto** : should tracking be turned on by default? ( _false_ is default )
|
|
188
|
+
- auto tracking means when any model is saved/updated/reloaded the tracker will save
|
|
189
|
+
the current state, allowing you to rollback anytime
|
|
190
|
+
- **enableIsDirty** : sets up computed properties on a model
|
|
191
|
+
- ```hasDirtyRelations``` for checking on changed relationships
|
|
192
|
+
- ```isDirty``` for checking on any changes
|
|
193
|
+
- NOTE: not working for object type attributes, since those are too
|
|
194
|
+
difficult to observe for the purpose of computed properties
|
|
195
|
+
|
|
196
|
+
- Model configuration
|
|
197
|
+
- Takes precedence over global
|
|
198
|
+
- So, globally auto track could be off, but on one model you can turn it on
|
|
199
|
+
- The options available are:
|
|
200
|
+
- **trackHasMany** : same as global trackHasMany
|
|
201
|
+
- **auto** : same as global auto
|
|
202
|
+
- **only** : limit the attributes/associations tracked on this model to just these
|
|
203
|
+
- **except** : don't include these attributes/associations
|
|
204
|
+
- You can use 'only' and 'except' at the same time, but you could also clean your nose with a pipe cleaner
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
// file config/environment.js
|
|
208
|
+
var ENV = {
|
|
209
|
+
modulePrefix: 'dummy',
|
|
210
|
+
environment: environment,
|
|
211
|
+
rootURL: '/',
|
|
212
|
+
locationType: 'auto',
|
|
213
|
+
changeTracker: { trackHasMany: true, auto: true },
|
|
214
|
+
EmberENV: {
|
|
215
|
+
... rest of config
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
- Set options on the model
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
// file app/models/user.js
|
|
222
|
+
export default Model.extend({
|
|
223
|
+
changeTracker: {only: ['info', 'company', 'pets']}, // settings for user models
|
|
224
|
+
|
|
225
|
+
name: attr('string'),
|
|
226
|
+
info: attr('object'),
|
|
227
|
+
json: attr(),
|
|
228
|
+
company: belongsTo('company', { async: false, polymorphic: true }),
|
|
229
|
+
profile: belongsTo('profile', { async: true }),
|
|
230
|
+
projects: hasMany('project', { async: false }),
|
|
231
|
+
pets: hasMany('pet', { async: true, polymorphic: true })
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Serializer extras
|
|
236
|
+
- Mixin is provided that will allow you to remove any attributes/associations
|
|
237
|
+
that did not change from the serialized json
|
|
238
|
+
- Useful when you want to reduce the size of a json payload
|
|
239
|
+
- removing unchanged values can be big reduction at times
|
|
240
|
+
|
|
241
|
+
Example:
|
|
242
|
+
|
|
243
|
+
Let's say you set up the user model's serializer with keep-only-changed mixin
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
// file: app/serializers/user.js
|
|
247
|
+
import DS from 'ember-data';
|
|
248
|
+
import keepOnlyChanged from 'ember-data-change-tracker/mixins/keep-only-changed';
|
|
249
|
+
|
|
250
|
+
export default DS.RESTSerializer.extend(keepOnlyChanged);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Then when you are updating the user model
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
user.set('info.foo', 1);
|
|
257
|
+
user.serialize(); //=> '{ info: {"foo:1"} }'
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Without this mixin enabled the json would look like:
|
|
261
|
+
```javascript
|
|
262
|
+
{ name: "dude", info: {"foo:1"}, company: "1" companyType: "company", profile: "1" }
|
|
263
|
+
```
|
|
264
|
+
where all the attributes and association are included whether they changed or not
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
## Extra's
|
|
268
|
+
- Adds a few more helpful methods to ember data model
|
|
269
|
+
- ```didChange(key) ```
|
|
270
|
+
- did the value on this key change?
|
|
271
|
+
- ```savedTrackerValue(key)```
|
|
272
|
+
- this is the value that the key had after it was created/saved and
|
|
273
|
+
before any modifications
|
|
274
|
+
|
|
275
|
+
Usage:
|
|
276
|
+
```javascript
|
|
277
|
+
user.startTrack(); // saves all keys that are being tracked
|
|
278
|
+
user.savedTrackerValue('info') //=> {foo: 1} original value of info
|
|
279
|
+
user.set('info.foo', 8)
|
|
280
|
+
user.didChange('info') //=> true
|
|
281
|
+
user.savedTrackerValue('info') //=> {foo: 1} original value of info
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Known Issues
|
|
285
|
+
- When pushing data to the store directly to create a model ( usually done when using
|
|
286
|
+
websockets .. but same issue if using factory guy) you need to call ```model.saveTrackerChanges()```
|
|
287
|
+
manually after creating that new model
|
|
288
|
+
- Testing
|
|
289
|
+
- In unit / integration tests you have to manually initialize change-tracker
|
|
290
|
+
if you are testing anything that requires the addon to be enabled
|
|
291
|
+
|
|
292
|
+
For example:
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
|
|
296
|
+
import {moduleForModel, test} from 'ember-qunit';
|
|
297
|
+
import {make, manualSetup} from 'ember-data-factory-guy';
|
|
298
|
+
import {initializer as changeInitializer} from 'ember-data-change-tracker';
|
|
299
|
+
|
|
300
|
+
moduleForModel('project', 'Unit | Model | project', {
|
|
301
|
+
|
|
302
|
+
beforeEach() {
|
|
303
|
+
manualSetup(this.container);
|
|
304
|
+
changeInitializer();
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
```
|
package/addon/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Ember from 'ember';
|
|
2
|
+
|
|
3
|
+
// EmberData does not serialize hasMany relationships by default
|
|
4
|
+
export default Ember.Mixin.create({
|
|
5
|
+
keepValue(record, key) {
|
|
6
|
+
return record.get('isNew') || record.didChange(key);
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
serializeAttribute: function(snapshot, json, key) {
|
|
10
|
+
if (this.keepValue(snapshot.record, key)) {
|
|
11
|
+
return this._super(...arguments);
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
serializeBelongsTo: function(snapshot, json, relationship) {
|
|
16
|
+
if (this.keepValue(snapshot.record, relationship.key)) {
|
|
17
|
+
return this._super(...arguments);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
serializeHasMany: function(snapshot, json, relationship) {
|
|
22
|
+
if (this.keepValue(snapshot.record, relationship.key)) {
|
|
23
|
+
return this._super(...arguments);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import Ember from 'ember';
|
|
2
|
+
import Model from 'ember-data/model';
|
|
3
|
+
import Tracker from './tracker';
|
|
4
|
+
|
|
5
|
+
Model.reopen({
|
|
6
|
+
|
|
7
|
+
init(){
|
|
8
|
+
this._super(...arguments);
|
|
9
|
+
if (Tracker.isAutoSaveEnabled(this)) {
|
|
10
|
+
this.initTracking();
|
|
11
|
+
}
|
|
12
|
+
if (Tracker.isIsDirtyEnabled(this)) {
|
|
13
|
+
// this is experimental
|
|
14
|
+
Tracker.initializeDirtiness(this);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
this.setupTrackerMetaData();
|
|
18
|
+
this.setupUnknownRelationshipLoadObservers();
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Did an attribute/association change?
|
|
23
|
+
*
|
|
24
|
+
* @param {String} key the attribute/association name
|
|
25
|
+
* @param {Object} changed optional ember-data changedAttribute object
|
|
26
|
+
* @returns {Boolean} true if value changed
|
|
27
|
+
*/
|
|
28
|
+
didChange(key, changed, options) {
|
|
29
|
+
return Tracker.didChange(this, key, changed, options);
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Did any attribute/association change?
|
|
34
|
+
*
|
|
35
|
+
* returns object with:
|
|
36
|
+
* {key: value} = {attribute: true}
|
|
37
|
+
*
|
|
38
|
+
* If the the attribute changed, it will be included in this object
|
|
39
|
+
*
|
|
40
|
+
* @returns {*}
|
|
41
|
+
*/
|
|
42
|
+
modelChanges() {
|
|
43
|
+
let changed = Ember.assign({}, this.changedAttributes());
|
|
44
|
+
let trackerInfo = Tracker.metaInfo(this);
|
|
45
|
+
for (let key in trackerInfo) {
|
|
46
|
+
if (!changed[key] && trackerInfo.hasOwnProperty(key)) {
|
|
47
|
+
if (this.didChange(key, changed)) {
|
|
48
|
+
changed[key] = true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return changed;
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Rollback all the changes on this model, for the keys you are
|
|
57
|
+
* tracking.
|
|
58
|
+
*
|
|
59
|
+
* NOTE: Be sure you understand what keys you are tracking.
|
|
60
|
+
* By default, tracker will save all keys, but if you set up
|
|
61
|
+
* a model to 'only' track a limited set of keys, then the rollback
|
|
62
|
+
* will only be limited to those keys
|
|
63
|
+
*
|
|
64
|
+
*/
|
|
65
|
+
rollback() {
|
|
66
|
+
const isNew = this.get('isNew');
|
|
67
|
+
this.rollbackAttributes();
|
|
68
|
+
if (isNew) { return; }
|
|
69
|
+
let trackerInfo = Tracker.metaInfo(this);
|
|
70
|
+
let rollbackData = Tracker.rollbackData(this, trackerInfo);
|
|
71
|
+
let normalized = Tracker.normalize(this, rollbackData);
|
|
72
|
+
this.store.push(normalized);
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// alias for saveChanges method
|
|
76
|
+
startTrack() {
|
|
77
|
+
this.initTracking();
|
|
78
|
+
this.saveChanges();
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// Ember Data DS.Model events
|
|
82
|
+
// http://api.emberjs.com/ember-data/3.10/classes/DS.Model/events
|
|
83
|
+
//
|
|
84
|
+
// Replaces deprecated Ember.Evented usage:
|
|
85
|
+
// https://github.com/emberjs/rfcs/blob/master/text/0329-deprecated-ember-evented-in-ember-data.md
|
|
86
|
+
// Related: https://github.com/emberjs/rfcs/pull/329
|
|
87
|
+
|
|
88
|
+
onIsNewChanged() {
|
|
89
|
+
if (this.isNew === false) {
|
|
90
|
+
this.saveOnCreate()
|
|
91
|
+
this.removeObserver('isNew', this, this.onIsNewChanged);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
onIsDeletedChanged() {
|
|
96
|
+
if (this.isDeleted === true) {
|
|
97
|
+
this.clearSavedAttributes();
|
|
98
|
+
this.removeObserver('isDeleted', this, this.onIsDeletedChanged);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
onIsLoadedChanged() {
|
|
103
|
+
this.setupTrackerMetaData();
|
|
104
|
+
this.setupUnknownRelationshipLoadObservers();
|
|
105
|
+
this.removeObserver('isLoaded', this, this.onIsLoadedChanged);
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
initTracking(){
|
|
109
|
+
// sync tracker with model on events like create/update/delete/load
|
|
110
|
+
if (this.isNew) {
|
|
111
|
+
this.addObserver('isNew', this, this.onIsNewChanged)
|
|
112
|
+
}
|
|
113
|
+
this.addObserver('isDeleted', this, this.onIsDeletedChanged)
|
|
114
|
+
|
|
115
|
+
if (!this.isLoaded) {
|
|
116
|
+
this.addObserver('isLoaded', this, this.onIsLoadedChanged);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// there is no didUpdate hook anymore and no appropriate model props to base on
|
|
120
|
+
// saveOnUpdate should be called after model has been saved
|
|
121
|
+
// right after model
|
|
122
|
+
Tracker.setupTracking(this);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Save the current state of the model
|
|
127
|
+
*
|
|
128
|
+
* NOTE: This is needed when manually pushing data
|
|
129
|
+
* to the store and ussing Ember < 2.10
|
|
130
|
+
*
|
|
131
|
+
* options like => {except: 'company'}
|
|
132
|
+
*
|
|
133
|
+
* @param {Object} options
|
|
134
|
+
*/
|
|
135
|
+
saveChanges(options) {
|
|
136
|
+
Tracker.setupTracking(this);
|
|
137
|
+
Tracker.saveChanges(this, options);
|
|
138
|
+
Tracker.triggerIsDirtyReset(this);
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
saveTrackerChanges(options) {
|
|
143
|
+
this.saveChanges(options);
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get value of the last known value tracker is saving for this key
|
|
148
|
+
*
|
|
149
|
+
* @param {String} key attribute/association name
|
|
150
|
+
* @returns {*}
|
|
151
|
+
*/
|
|
152
|
+
savedTrackerValue(key) {
|
|
153
|
+
return Tracker.lastValue(this, key);
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
// save state when model is loaded or created if using auto save
|
|
157
|
+
setupTrackerMetaData() {
|
|
158
|
+
if (Tracker.isIsDirtyEnabled(this)) {
|
|
159
|
+
// this is experimental
|
|
160
|
+
Tracker.initializeDirtiness(this);
|
|
161
|
+
}
|
|
162
|
+
if (Tracker.isAutoSaveEnabled(this)) {
|
|
163
|
+
this.saveChanges();
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
// watch for relationships loaded with data via links
|
|
168
|
+
setupUnknownRelationshipLoadObservers() {
|
|
169
|
+
this.eachRelationship((key) => {
|
|
170
|
+
this.addObserver(key, this, 'observeUnknownRelationshipLoaded');
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// when model updates, update the tracked state if using auto save
|
|
175
|
+
saveOnUpdate() {
|
|
176
|
+
if (Tracker.isAutoSaveEnabled(this) || Tracker.isIsDirtyEnabled(this)) {
|
|
177
|
+
this.saveChanges();
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
// when model creates, update the tracked state if using auto save
|
|
182
|
+
saveOnCreate() {
|
|
183
|
+
if (Tracker.isAutoSaveEnabled(this) || Tracker.isIsDirtyEnabled(this)) {
|
|
184
|
+
this.saveChanges();
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
// There is no didReload callback on models, so have to override reload
|
|
189
|
+
reload() {
|
|
190
|
+
let promise = this._super(...arguments);
|
|
191
|
+
promise.then(() => {
|
|
192
|
+
if (Tracker.isAutoSaveEnabled(this)) {
|
|
193
|
+
this.saveChanges();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
return promise;
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// when model deletes, remove any tracked state
|
|
200
|
+
clearSavedAttributes() {
|
|
201
|
+
Tracker.clear(this);
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
observeUnknownRelationshipLoaded(sender, key/*, value, rev*/) {
|
|
205
|
+
if (Tracker.trackingIsSetup(this) && Tracker.isTracking(this, key)) {
|
|
206
|
+
let saved = Tracker.saveLoadedRelationship(this, key);
|
|
207
|
+
if (saved) {
|
|
208
|
+
this.removeObserver(key, this, 'observeUnknownRelationshipLoaded');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|