Skip to content

Commit 2edb6fa

Browse files
committed
Added model events. #170
1 parent 09d4fc9 commit 2edb6fa

File tree

10 files changed

+449
-144
lines changed

10 files changed

+449
-144
lines changed

dist/angular-data.js

+347-103
Large diffs are not rendered by default.

dist/angular-data.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/datastore/async_methods/create.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -97,24 +97,26 @@ function create(resourceName, attrs, options) {
9797
return func.call(attrs, resourceName, attrs);
9898
})
9999
.then(function (attrs) {
100+
DS.notify(definition, 'beforeCreate', DS.utils.merge({}, attrs));
100101
return DS.adapters[options.adapter || definition.defaultAdapter].create(definition, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), options);
101102
})
102103
.then(function (res) {
103104
var func = options.afterCreate ? DS.$q.promisify(options.afterCreate) : definition.afterCreate;
104105
var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res);
105106
return func.call(attrs, resourceName, attrs);
106107
})
107-
.then(function (data) {
108+
.then(function (attrs) {
109+
DS.notify(definition, 'afterCreate', DS.utils.merge({}, attrs));
108110
if (options.cacheResponse) {
109111
var resource = DS.store[resourceName];
110-
var created = DS.inject(definition.name, data, options);
112+
var created = DS.inject(definition.name, attrs, options);
111113
var id = created[definition.idAttribute];
112114
resource.completedQueries[id] = new Date().getTime();
113115
resource.previousAttributes[id] = DS.utils.deepMixIn({}, created);
114116
resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]);
115117
return DS.get(definition.name, id);
116118
} else {
117-
return DS.createInstance(resourceName, data, options);
119+
return DS.createInstance(resourceName, attrs, options);
118120
}
119121
});
120122
}

src/datastore/async_methods/destroy.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,16 @@ function destroy(resourceName, id, options) {
7272
var func = options.beforeDestroy ? DS.$q.promisify(options.beforeDestroy) : definition.beforeDestroy;
7373
return func.call(attrs, resourceName, attrs);
7474
})
75-
.then(function () {
75+
.then(function (attrs) {
76+
DS.notify(definition, 'beforeDestroy', DS.utils.merge({}, attrs));
7677
return DS.adapters[options.adapter || definition.defaultAdapter].destroy(definition, id, options);
7778
})
7879
.then(function () {
7980
var func = options.afterDestroy ? DS.$q.promisify(options.afterDestroy) : definition.afterDestroy;
8081
return func.call(item, resourceName, item);
8182
})
8283
.then(function () {
84+
DS.notify(definition, 'afterDestroy', DS.utils.merge({}, item));
8385
DS.eject(resourceName, id);
8486
return id;
8587
});

src/datastore/async_methods/save.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ function save(resourceName, id, options) {
9898
return func.call(attrs, resourceName, attrs);
9999
})
100100
.then(function (attrs) {
101+
DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs));
101102
if (options.changesOnly) {
102103
var resource = DS.store[resourceName];
103104
resource.observers[id].deliver();
@@ -125,16 +126,17 @@ function save(resourceName, id, options) {
125126
var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res);
126127
return func.call(attrs, resourceName, attrs);
127128
})
128-
.then(function (data) {
129+
.then(function (attrs) {
130+
DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs));
129131
if (options.cacheResponse) {
130132
var resource = DS.store[resourceName];
131-
var saved = DS.inject(definition.name, data, options);
133+
var saved = DS.inject(definition.name, attrs, options);
132134
resource.previousAttributes[id] = DS.utils.deepMixIn({}, saved);
133135
resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]);
134136
resource.observers[id].discardChanges();
135137
return DS.get(resourceName, id);
136138
} else {
137-
return data;
139+
return attrs;
138140
}
139141
});
140142
} catch (err) {

src/datastore/async_methods/update.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -97,24 +97,26 @@ function update(resourceName, id, attrs, options) {
9797
return func.call(attrs, resourceName, attrs);
9898
})
9999
.then(function (attrs) {
100+
DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs));
100101
return DS.adapters[options.adapter || definition.defaultAdapter].update(definition, id, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), options);
101102
})
102103
.then(function (res) {
103104
var func = options.afterUpdate ? DS.$q.promisify(options.afterUpdate) : definition.afterUpdate;
104105
var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res);
105106
return func.call(attrs, resourceName, attrs);
106107
})
107-
.then(function (data) {
108+
.then(function (attrs) {
109+
DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs));
108110
if (options.cacheResponse) {
109111
var resource = DS.store[resourceName];
110-
var updated = DS.inject(definition.name, data, options);
112+
var updated = DS.inject(definition.name, attrs, options);
111113
var id = updated[definition.idAttribute];
112114
resource.previousAttributes[id] = DS.utils.deepMixIn({}, updated);
113115
resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]);
114116
resource.observers[id].discardChanges();
115117
return DS.get(definition.name, id);
116118
} else {
117-
return data;
119+
return attrs;
118120
}
119121
});
120122
} catch (err) {

src/datastore/async_methods/updateAll.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,20 @@ function updateAll(resourceName, attrs, params, options) {
109109
return func.call(attrs, resourceName, attrs);
110110
})
111111
.then(function (attrs) {
112+
DS.notify(definition, 'beforeUpdate', DS.utils.merge({}, attrs));
112113
return DS.adapters[options.adapter || definition.defaultAdapter].updateAll(definition, options.serialize ? options.serialize(resourceName, attrs) : definition.serialize(resourceName, attrs), params, options);
113114
})
114115
.then(function (res) {
115116
var func = options.afterUpdate ? DS.$q.promisify(options.afterUpdate) : definition.afterUpdate;
116117
var attrs = options.deserialize ? options.deserialize(resourceName, res) : definition.deserialize(resourceName, res);
117118
return func.call(attrs, resourceName, attrs);
118119
})
119-
.then(function (data) {
120+
.then(function (attrs) {
121+
DS.notify(definition, 'afterUpdate', DS.utils.merge({}, attrs));
120122
if (options.cacheResponse) {
121-
return DS.inject(definition.name, data, options);
123+
return DS.inject(definition.name, attrs, options);
122124
} else {
123-
return data;
125+
return attrs;
124126
}
125127
});
126128
} catch (err) {

src/datastore/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Defaults.prototype.defaultFilter = function (collection, resourceName, params, o
7676
keep = first ? (attrs[field] <= val) : keep && (attrs[field] <= val);
7777
} else if (op === 'in') {
7878
keep = first ? _this.utils.contains(val, attrs[field]) : keep && _this.utils.contains(val, attrs[field]);
79-
} else if (op === 'notIn') {
79+
} else if (op === 'notIn') {
8080
keep = first ? !_this.utils.contains(val, attrs[field]) : keep && !_this.utils.contains(val, attrs[field]);
8181
} else if (op === '|==') {
8282
keep = first ? (attrs[field] == val) : keep || (attrs[field] == val);
@@ -660,6 +660,7 @@ function DSProvider() {
660660
var args = Array.prototype.slice.call(arguments, 2);
661661
args.unshift(definition.name);
662662
args.unshift('DS.' + event);
663+
definition.emit.apply(definition, args);
663664
if (definition.events === 'broadcast') {
664665
$rootScope.$broadcast.apply($rootScope, args);
665666
} else if (definition.events === 'emit') {

src/datastore/sync_methods/defineResource.js

+28-24
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,23 @@ var methodsToProxy = [
107107
*/
108108
function defineResource(definition) {
109109
var DS = this;
110+
var DSUtils = DS.utils;
110111
var definitions = DS.definitions;
111112
var IA = DS.errors.IA;
112113

113-
if (DS.utils.isString(definition)) {
114+
if (DSUtils.isString(definition)) {
114115
definition = definition.replace(/\s/gi, '');
115116
definition = {
116117
name: definition
117118
};
118119
}
119-
if (!DS.utils.isObject(definition)) {
120+
if (!DSUtils.isObject(definition)) {
120121
throw new IA(errorPrefix + 'definition: Must be an object!');
121-
} else if (!DS.utils.isString(definition.name)) {
122+
} else if (!DSUtils.isString(definition.name)) {
122123
throw new IA(errorPrefix + 'definition.name: Must be a string!');
123-
} else if (definition.idAttribute && !DS.utils.isString(definition.idAttribute)) {
124+
} else if (definition.idAttribute && !DSUtils.isString(definition.idAttribute)) {
124125
throw new IA(errorPrefix + 'definition.idAttribute: Must be a string!');
125-
} else if (definition.endpoint && !DS.utils.isString(definition.endpoint)) {
126+
} else if (definition.endpoint && !DSUtils.isString(definition.endpoint)) {
126127
throw new IA(errorPrefix + 'definition.endpoint: Must be a string!');
127128
} else if (DS.store[definition.name]) {
128129
throw new DS.errors.R(errorPrefix + definition.name + ' is already registered!');
@@ -131,20 +132,20 @@ function defineResource(definition) {
131132
try {
132133
// Inherit from global defaults
133134
Resource.prototype = DS.defaults;
134-
definitions[definition.name] = new Resource(DS.utils, definition);
135+
definitions[definition.name] = new Resource(DSUtils, definition);
135136

136137
var def = definitions[definition.name];
137138

138139
// Setup nested parent configuration
139140
if (def.relations) {
140141
def.relationList = [];
141142
def.relationFields = [];
142-
DS.utils.forOwn(def.relations, function (relatedModels, type) {
143-
DS.utils.forOwn(relatedModels, function (defs, relationName) {
144-
if (!DS.utils.isArray(defs)) {
143+
DSUtils.forOwn(def.relations, function (relatedModels, type) {
144+
DSUtils.forOwn(relatedModels, function (defs, relationName) {
145+
if (!DSUtils.isArray(defs)) {
145146
relatedModels[relationName] = [defs];
146147
}
147-
DS.utils.forEach(relatedModels[relationName], function (d) {
148+
DSUtils.forEach(relatedModels[relationName], function (d) {
148149
d.type = type;
149150
d.relation = relationName;
150151
d.name = def.name;
@@ -154,17 +155,17 @@ function defineResource(definition) {
154155
});
155156
});
156157
if (def.relations.belongsTo) {
157-
DS.utils.forOwn(def.relations.belongsTo, function (relatedModel, modelName) {
158-
DS.utils.forEach(relatedModel, function (relation) {
158+
DSUtils.forOwn(def.relations.belongsTo, function (relatedModel, modelName) {
159+
DSUtils.forEach(relatedModel, function (relation) {
159160
if (relation.parent) {
160161
def.parent = modelName;
161162
def.parentKey = relation.localKey;
162163
}
163164
});
164165
});
165166
}
166-
DS.utils.deepFreeze(def.relations);
167-
DS.utils.deepFreeze(def.relationList);
167+
DSUtils.deepFreeze(def.relations);
168+
DSUtils.deepFreeze(def.relationList);
168169
}
169170

170171
def.getEndpoint = function (attrs, options) {
@@ -177,17 +178,17 @@ function defineResource(definition) {
177178
options = options || {};
178179
options.params = options.params || {};
179180
if (parent && parentKey && definitions[parent] && options.params[parentKey] !== false) {
180-
if (DS.utils.isNumber(attrs) || DS.utils.isString(attrs)) {
181+
if (DSUtils.isNumber(attrs) || DSUtils.isString(attrs)) {
181182
item = DS.get(this.name, attrs);
182183
}
183-
if (DS.utils.isObject(attrs) && parentKey in attrs) {
184+
if (DSUtils.isObject(attrs) && parentKey in attrs) {
184185
delete options.params[parentKey];
185-
endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), attrs[parentKey], thisEndpoint);
186+
endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), attrs[parentKey], thisEndpoint);
186187
} else if (item && parentKey in item) {
187188
delete options.params[parentKey];
188-
endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), item[parentKey], thisEndpoint);
189+
endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), item[parentKey], thisEndpoint);
189190
} else if (options && options.params[parentKey]) {
190-
endpoint = DS.utils.makePath(definitions[parent].getEndpoint(attrs, options), options.params[parentKey], thisEndpoint);
191+
endpoint = DSUtils.makePath(definitions[parent].getEndpoint(attrs, options), options.params[parentKey], thisEndpoint);
191192
delete options.params[parentKey];
192193
}
193194
}
@@ -212,7 +213,7 @@ function defineResource(definition) {
212213
deleteOnExpire: def.deleteOnExpire || 'none',
213214
onExpire: function (id) {
214215
var item = DS.eject(def.name, id);
215-
if (DS.utils.isFunction(def.onExpire)) {
216+
if (DSUtils.isFunction(def.onExpire)) {
216217
def.onExpire(id, item);
217218
}
218219
},
@@ -224,18 +225,18 @@ function defineResource(definition) {
224225
});
225226

226227
// Create the wrapper class for the new resource
227-
def.class = DS.utils.pascalCase(definition.name);
228+
def.class = DSUtils.pascalCase(definition.name);
228229
eval('function ' + def.class + '() {}');
229230
def[def.class] = eval(def.class);
230231

231232
// Apply developer-defined methods
232233
if (def.methods) {
233-
DS.utils.deepMixIn(def[def.class].prototype, def.methods);
234+
DSUtils.deepMixIn(def[def.class].prototype, def.methods);
234235
}
235236

236237
// Prepare for computed properties
237238
if (def.computed) {
238-
DS.utils.forOwn(def.computed, function (fn, field) {
239+
DSUtils.forOwn(def.computed, function (fn, field) {
239240
if (angular.isFunction(fn)) {
240241
def.computed[field] = [fn];
241242
fn = def.computed[field];
@@ -257,7 +258,7 @@ function defineResource(definition) {
257258
angular.forEach(deps, function (val, index) {
258259
deps[index] = val.trim();
259260
});
260-
fn.deps = DS.utils.filter(deps, function (dep) {
261+
fn.deps = DSUtils.filter(deps, function (dep) {
261262
return !!dep;
262263
});
263264
});
@@ -309,6 +310,9 @@ function defineResource(definition) {
309310
def.beforeDestroy = DS.$q.promisify(def.beforeDestroy);
310311
def.afterDestroy = DS.$q.promisify(def.afterDestroy);
311312

313+
// Mix-in events
314+
DSUtils.Events(def);
315+
312316
return def;
313317
} catch (err) {
314318
DS.$log.error(err);

src/utils.js

+47-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,47 @@
1+
function Events(target) {
2+
var events = {};
3+
target = target || this;
4+
/**
5+
* On: listen to events
6+
*/
7+
target.on = function (type, func, ctx) {
8+
events[type] = events[type] || [];
9+
events[type].push({
10+
f: func,
11+
c: ctx
12+
});
13+
};
14+
15+
/**
16+
* Off: stop listening to event / specific callback
17+
*/
18+
target.off = function (type, func) {
19+
var listeners = events[type];
20+
if (!listeners) {
21+
events = {};
22+
} else if (func) {
23+
for (var i = 0; i < listeners.length; i++) {
24+
if (listeners[i] === func) {
25+
listeners.splice(i, 1);
26+
break;
27+
}
28+
}
29+
} else {
30+
listeners.splice(0, listeners.length);
31+
}
32+
};
33+
34+
target.emit = function () {
35+
var args = Array.prototype.slice.call(arguments);
36+
var listeners = events[args.shift()] || [];
37+
if (listeners) {
38+
for (var i = 0; i < listeners.length; i++) {
39+
listeners[i].f.apply(listeners[i].c, args);
40+
}
41+
}
42+
};
43+
}
44+
145
module.exports = [function () {
246
return {
347
isBoolean: require('mout/lang/isBoolean'),
@@ -16,6 +60,7 @@ module.exports = [function () {
1660
forEach: angular.forEach,
1761
pick: require('mout/object/pick'),
1862
set: require('mout/object/set'),
63+
merge: require('mout/object/merge'),
1964
contains: require('mout/array/contains'),
2065
filter: require('mout/array/filter'),
2166
toLookup: require('mout/array/toLookup'),
@@ -79,6 +124,7 @@ module.exports = [function () {
79124
removed: removed,
80125
changed: changed
81126
};
82-
}
127+
},
128+
Events: Events
83129
};
84130
}];

0 commit comments

Comments
 (0)