diff --git a/firebase-firestore-mixin.html b/firebase-firestore-mixin.html
index b4e9a19..8036f33 100644
--- a/firebase-firestore-mixin.html
+++ b/firebase-firestore-mixin.html
@@ -6,10 +6,6 @@
{
const PROPERTY_BINDING_REGEXP = /{([^{]+)}/g;
- const TRANSFORMS = {
- doc: function(snap) { return iDoc(snap); },
- collection: function(snap) { return snap.empty ? [] : snap.docs.map(doc => iDoc(doc)) }
- }
const isOdd = (x) => x & 1 === 1;
@@ -31,14 +27,14 @@
return whole;
}
- const collect = (what, which) => {
- let res = {};
- while (what) {
- res = Object.assign({}, what[which], res); // Respect prototype priority
- what = Object.getPrototypeOf(what);
- }
- return res;
- };
+ const collect = (what, which) => {
+ let res = {};
+ while (what) {
+ res = Object.assign({}, what[which], res); // Respect prototype priority
+ what = Object.getPrototypeOf(what);
+ }
+ return res;
+ };
const iDoc = (snap) => {
if (snap.exists) {
@@ -157,18 +153,17 @@
this._firestoreProps[name] = config;
- // Create a method observer that will be called every time a templatized or observed property changes
- let args = config.props.concat(config.observes).join(',');
- if (args.length) { args = ',' + args; }
- this._createMethodObserver(`_firestoreUpdateBinding('${type}','${name}'${args})`);
-
if (!config.props.length && !config.observes.length) {
- this._firestoreUpdateBinding(type,name);
+ this._firestoreUpdateBinding(name, type);
+ } else {
+ // Create a method observer that will be called every time a templatized or observed property changes
+ let args = config.props.concat(config.observes).join(',');
+ this._createMethodObserver(`_firestoreUpdateBinding('${name}', '${type}', ${args})`);
}
}
- _firestoreUpdateBinding(type, name) {
- this._firestoreUnlisten(name);
+ _firestoreUpdateBinding(name, type) {
+ this._firestoreUnlisten(name, type);
const config = this._firestoreProps[name];
const propArgs = Array.prototype.slice.call(arguments, 2, config.props.length + 2).filter(arg => arg);
@@ -182,10 +177,7 @@
}
const collPath = stitch(config.literals, propArgs);
- const assigner = snap => {
- this[name] = TRANSFORMS[type](snap);
- this[name + 'Ready'] = true;
- }
+ const assigner = this._firestoreAssigner(name, type);
let ref = this.db[type](collPath);
this[name + 'Ref'] = ref;
@@ -203,11 +195,57 @@
}
}
- _firestoreUnlisten(name) {
+ _firestoreUnlisten(name, type) {
if (this._firestoreListeners[name]) {
this._firestoreListeners[name]();
delete this._firestoreListeners[name];
}
+
+ this[name] = type === 'collection' ? [] : null;
+ }
+
+ _firestoreAssigner(name, type) {
+ if (type === 'doc') {
+ return (snap) => this._firestoreAssignDocument(name, snap);
+ } else if (type === 'collection') {
+ return (snap) => this._firestoreAssignCollection(name, snap);
+ } else {
+ throw new Error('Unknown listener type.');
+ }
+ }
+
+ _firestoreAssignDocument(name, snap) {
+ this[name] = iDoc(snap);
+ this[name + 'Ready'] = true;
+ }
+
+ _firestoreAssignCollection(name, snap) {
+ const propertyValueIsArray = Array.isArray(this[name])
+ const allDocumentsChanged = snap.docs.length === snap.docChanges.length;
+ if (propertyValueIsArray && allDocumentsChanged === false) {
+ snap.docChanges.forEach((change) => {
+ switch (change.type) {
+ case 'added':
+ this.splice(name, change.newIndex, 0, iDoc(change.doc));
+ break;
+ case 'removed':
+ this.splice(name, change.oldIndex, 1);
+ break;
+ case 'modified':
+ if (change.oldIndex === change.newIndex) {
+ this.splice(name, change.oldIndex, 1, iDoc(change.doc));
+ } else {
+ this.splice(name, change.oldIndex, 1);
+ this.splice(name, change.newIndex, 0, iDoc(change.doc));
+ }
+ break;
+ default:
+ throw new Error(`Unhandled document change: ${change.type}.`);
+ }
+ });
+ } else {
+ this[name] = snap.docs.map(iDoc);
+ }
}
}
}