|
12 | 12 | * $$moved - called whenever a child_moved event occurs |
13 | 13 | * $$removed - called whenever a child_removed event occurs |
14 | 14 | * $$error - called when listeners are canceled due to a security error |
| 15 | + * $$process - called immediately after $$added/$$updated/$$moved/$$removed |
| 16 | + * to splice/manipulate the array and invokes $$notify |
| 17 | + * |
| 18 | + * Additionally, there is one more method of interest to devs extending this class: |
| 19 | + * $$notify - triggers notifications to any $watch listeners, called by $$process |
15 | 20 | * |
16 | 21 | * Instead of directly modifying this class, one should generally use the $extendFactory |
17 | | - * method to add or change how methods behave: |
| 22 | + * method to add or change how methods behave. $extendFactory modifies the prototype of |
| 23 | + * the array class by returning a clone of $FirebaseArray. |
18 | 24 | * |
19 | 25 | * <pre><code> |
20 | 26 | * var NewFactory = $FirebaseArray.$extendFactory({ |
21 | 27 | * // add a new method to the prototype |
22 | 28 | * foo: function() { return 'bar'; }, |
23 | 29 | * |
24 | 30 | * // change how records are created |
25 | | - * $$added: function(snap) { |
26 | | - * var rec = new Widget(snap); |
27 | | - * this._process('child_added', rec); |
| 31 | + * $$added: function(snap, prevChild) { |
| 32 | + * return new Widget(snap, prevChild); |
| 33 | + * }, |
| 34 | + * |
| 35 | + * // change how records are updated |
| 36 | + * $$updated: function(snap) { |
| 37 | + * return this.$getRecord(snap.key()).update(snap); |
28 | 38 | * } |
29 | 39 | * }); |
30 | 40 | * </code></pre> |
31 | 41 | * |
32 | | - * And then the new factory can be used by passing it as an argument: |
| 42 | + * And then the new factory can be passed as an argument: |
33 | 43 | * <code>$firebase( firebaseRef, {arrayFactory: NewFactory}).$asArray();</code> |
34 | 44 | */ |
35 | 45 | angular.module('firebase').factory('$FirebaseArray', ["$log", "$firebaseUtils", |
|
108 | 118 | if( key !== null ) { |
109 | 119 | return self.$inst().$set(key, $firebaseUtils.toJSON(item)) |
110 | 120 | .then(function(ref) { |
111 | | - self._notify('child_changed', key); |
| 121 | + self.$$notify('child_changed', key); |
112 | 122 | return ref; |
113 | 123 | }); |
114 | 124 | } |
|
251 | 261 | * Called by $firebase to inform the array when a new item has been added at the server. |
252 | 262 | * This method must exist on any array factory used by $firebase. |
253 | 263 | * |
254 | | - * @param snap |
| 264 | + * @param {object} snap a Firebase snapshot |
255 | 265 | * @param {string} prevChild |
| 266 | + * @return {object} the record to be inserted into the array |
256 | 267 | */ |
257 | | - $$added: function(snap, prevChild) { |
| 268 | + $$added: function(snap/*, prevChild*/) { |
258 | 269 | // check to make sure record does not exist |
259 | 270 | var i = this.$indexFor($firebaseUtils.getKey(snap)); |
260 | 271 | if( i === -1 ) { |
|
267 | 278 | rec.$priority = snap.getPriority(); |
268 | 279 | $firebaseUtils.applyDefaults(rec, this.$$defaults); |
269 | 280 |
|
270 | | - // add it to array and send notifications |
271 | | - this._process('child_added', rec, prevChild); |
| 281 | + return rec; |
272 | 282 | } |
| 283 | + return false; |
273 | 284 | }, |
274 | 285 |
|
275 | 286 | /** |
276 | 287 | * Called by $firebase whenever an item is removed at the server. |
277 | | - * This method must exist on any arrayFactory passed into $firebase |
| 288 | + * This method does not physically remove the objects, but instead |
| 289 | + * returns a boolean indicating whether it should be removed (and |
| 290 | + * taking any other desired actions before the remove completes). |
278 | 291 | * |
279 | | - * @param snap |
| 292 | + * @param {object} snap a Firebase snapshot |
| 293 | + * @return {boolean} true if item should be removed |
280 | 294 | */ |
281 | 295 | $$removed: function(snap) { |
282 | | - var rec = this.$getRecord($firebaseUtils.getKey(snap)); |
283 | | - if( angular.isObject(rec) ) { |
284 | | - this._process('child_removed', rec); |
285 | | - } |
| 296 | + return this.$indexFor($firebaseUtils.getKey(snap)) > -1; |
286 | 297 | }, |
287 | 298 |
|
288 | 299 | /** |
289 | 300 | * Called by $firebase whenever an item is changed at the server. |
290 | | - * This method must exist on any arrayFactory passed into $firebase |
| 301 | + * This method should apply the changes, including changes to data |
| 302 | + * and to $priority, and then return true if any changes were made. |
291 | 303 | * |
292 | | - * @param snap |
| 304 | + * @param {object} snap a Firebase snapshot |
| 305 | + * @return {boolean} true if any data changed |
293 | 306 | */ |
294 | 307 | $$updated: function(snap) { |
| 308 | + var changed = false; |
295 | 309 | var rec = this.$getRecord($firebaseUtils.getKey(snap)); |
296 | 310 | if( angular.isObject(rec) ) { |
297 | 311 | // apply changes to the record |
298 | | - var changed = $firebaseUtils.updateRec(rec, snap); |
| 312 | + changed = $firebaseUtils.updateRec(rec, snap); |
299 | 313 | $firebaseUtils.applyDefaults(rec, this.$$defaults); |
300 | | - if( changed ) { |
301 | | - this._process('child_changed', rec); |
302 | | - } |
303 | 314 | } |
| 315 | + return changed; |
304 | 316 | }, |
305 | 317 |
|
306 | 318 | /** |
307 | 319 | * Called by $firebase whenever an item changes order (moves) on the server. |
308 | | - * This method must exist on any arrayFactory passed into $firebase |
| 320 | + * This method should set $priority to the updated value and return true if |
| 321 | + * the record should actually be moved. It should not actually apply the move |
| 322 | + * operation. |
309 | 323 | * |
310 | | - * @param snap |
| 324 | + * @param {object} snap a Firebase snapshot |
311 | 325 | * @param {string} prevChild |
312 | 326 | */ |
313 | | - $$moved: function(snap, prevChild) { |
| 327 | + $$moved: function(snap/*, prevChild*/) { |
314 | 328 | var rec = this.$getRecord($firebaseUtils.getKey(snap)); |
315 | 329 | if( angular.isObject(rec) ) { |
316 | 330 | rec.$priority = snap.getPriority(); |
317 | | - this._process('child_moved', rec, prevChild); |
| 331 | + return true; |
318 | 332 | } |
| 333 | + return false; |
319 | 334 | }, |
320 | 335 |
|
321 | 336 | /** |
|
340 | 355 |
|
341 | 356 | /** |
342 | 357 | * Handles placement of recs in the array, sending notifications, |
343 | | - * and other internals. |
| 358 | + * and other internals. Called by the $firebase synchronization process |
| 359 | + * after $$added, $$updated, $$moved, and $$removed. |
344 | 360 | * |
345 | 361 | * @param {string} event one of child_added, child_removed, child_moved, or child_changed |
346 | 362 | * @param {object} rec |
347 | 363 | * @param {string} [prevChild] |
348 | 364 | * @private |
349 | 365 | */ |
350 | | - _process: function(event, rec, prevChild) { |
| 366 | + $$process: function(event, rec, prevChild) { |
351 | 367 | var key = this._getKey(rec); |
352 | 368 | var changed = false; |
353 | 369 | var pos; |
|
367 | 383 | changed = true; |
368 | 384 | break; |
369 | 385 | default: |
370 | | - // nothing to do |
| 386 | + throw new Error('Invalid event type: ' + event); |
371 | 387 | } |
372 | 388 | if( angular.isDefined(pos) ) { |
373 | 389 | // add it to the array |
374 | 390 | changed = this._addAfter(rec, prevChild) !== pos; |
375 | 391 | } |
376 | 392 | if( changed ) { |
377 | 393 | // send notifications to anybody monitoring $watch |
378 | | - this._notify(event, key, prevChild); |
| 394 | + this.$$notify(event, key, prevChild); |
379 | 395 | } |
380 | 396 | return changed; |
381 | 397 | }, |
382 | 398 |
|
383 | 399 | /** |
384 | 400 | * Used to trigger notifications for listeners registered using $watch |
| 401 | + * |
385 | 402 | * @param {string} event |
386 | 403 | * @param {string} key |
387 | 404 | * @param {string} [prevChild] |
388 | 405 | * @private |
389 | 406 | */ |
390 | | - _notify: function(event, key, prevChild) { |
| 407 | + $$notify: function(event, key, prevChild) { |
391 | 408 | var eventData = {event: event, key: key}; |
392 | 409 | if( angular.isDefined(prevChild) ) { |
393 | 410 | eventData.prevChild = prevChild; |
|
0 commit comments