diff --git a/README.md b/README.md index 4d1d03a..ded1195 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,14 @@ workflows. Example Usage: ```html + + ``` diff --git a/firebase-database-behavior.html b/firebase-database-behavior.html index 0cf7108..60c38af 100644 --- a/firebase-database-behavior.html +++ b/firebase-database-behavior.html @@ -46,7 +46,23 @@ disabled: { type: Boolean, value: false - } + }, + + /** + * `exists` is set to `true` when the data actually exists for the + * specified path; `false` otherwise. + * When we are unable to determine whether data exists or not + * (e.g. first round trip to the server not yet performed) the value + * is `null` + */ + exists: { + type: Boolean, + notify: true, + value: null, + readOnly: true, + reflectToAttribute: true + }, + }, observers: [ @@ -95,6 +111,8 @@ }, __pathChanged: function(path, oldPath) { + this._setExists(null); + if (!this.disabled && !this.valueIsEmpty(this.data)) { this.syncToMemory(function() { this.data = this.zeroValue; diff --git a/firebase-document.html b/firebase-document.html index d0538b1..3bfc618 100644 --- a/firebase-document.html +++ b/firebase-document.html @@ -160,11 +160,13 @@ __onFirebaseValue: function(snapshot) { var value = snapshot.val(); + var exists = true; if (value == null) { value = this.zeroValue; this.__needSetData = true; - } + exists = false; + } if (!this.isNew) { this.async(function() { @@ -188,6 +190,10 @@ } } }); + this._setExists(exists); + if(!exists) { + this.fire('empty-result'); + } }); } } diff --git a/firebase-firestore-mixin.html b/firebase-firestore-mixin.html index a7bcc07..8598ad4 100644 --- a/firebase-firestore-mixin.html +++ b/firebase-firestore-mixin.html @@ -169,10 +169,10 @@ this._firestoreProps = {}; this._firestoreListeners = {}; - this.db = this.constructor.db || firebase.firestore(); } connectedCallback() { + super.connectedCallback(); if (this[CONNECTED_CALLBACK_TOKEN] !== true) { this[CONNECTED_CALLBACK_TOKEN] = true; @@ -188,8 +188,6 @@ } } } - - super.connectedCallback(); } _firestoreBind(name, options) { @@ -205,6 +203,7 @@ this._firestoreProps[name] = config; const args = config.props.concat(config.observes); + this._firestoreUpdateBinding(name, ...args.map(x => this[x])); if (args.length > 0) { // Create a method observer that will be called every time // a templatized or observed property changes @@ -212,13 +211,10 @@ `_firestoreUpdateBinding('${name}', ${args.join(',')})` this._createMethodObserver(observer); } - - this._firestoreUpdateBinding(name, ...args.map(x => this[x])); } _firestoreUpdateBinding(name, ...args) { this._firestoreUnlisten(name); - const config = this._firestoreProps[name]; const isDefined = (x) => x !== undefined; const propArgs = args.slice(0, config.props.length).filter(isDefined); @@ -229,6 +225,7 @@ observesArgs.length === config.observes.length; if (propArgsReady && observesArgsReady) { + this.db = this.db || firebase.firestore(); const collPath = stitch(config.literals, propArgs); const assigner = this._firestoreAssigner(name, config); diff --git a/firebase-query.html b/firebase-query.html index d503f83..466d0d3 100644 --- a/firebase-query.html +++ b/firebase-query.html @@ -289,6 +289,7 @@ this.syncToMemory(function() { this.__map = {}; this.set('data', this.zeroValue); + this._setExists(null); }); } @@ -305,13 +306,14 @@ query.off('child_changed', this.__onFirebaseChildChanged, this); query.off('child_moved', this.__onFirebaseChildMoved, this); } - - this._onOnce = true; - this._query = query + + this._setExists(null); + this._onOnce = true; + this._query = query; // does the on-value first - query.off('value', this.__onFirebaseValue, this) - query.on('value', this.__onFirebaseValue, this.__onError, this) + query.off('value', this.__onFirebaseValue, this); + query.on('value', this.__onFirebaseValue, this.__onError, this); } }, @@ -338,6 +340,7 @@ }.bind(this)) this.set('data', data); + this._setExists(true); } const query = this.query @@ -371,6 +374,7 @@ this.__map[key] = value; this.splice('data', previousChildIndex + 1, 0, value); + this._setExists(true); }, __onFirebaseChildRemoved: function(snapshot) { @@ -390,6 +394,9 @@ this.splice('data', this.__indexFromKey(key), 1); } }); + if (this.data.length === 0) { + this._setExists(false); + } }); } }, diff --git a/firebase-storage-multiupload.html b/firebase-storage-multiupload.html index d1790b5..31a4422 100644 --- a/firebase-storage-multiupload.html +++ b/firebase-storage-multiupload.html @@ -53,7 +53,7 @@ * file-task * * * + name="test" + api-key="AIzaSyDTP-eiQezleFsV2WddFBAhF_WEzx_8v_g" + auth-domain="polymerfire-test.firebaseapp.com" + database-url="https://polymerfire-test.firebaseio.com"> diff --git a/test/firebase-common-behavior.html b/test/firebase-common-behavior.html index 8eba2b9..268ca2e 100644 --- a/test/firebase-common-behavior.html +++ b/test/firebase-common-behavior.html @@ -23,23 +23,23 @@ + name="test" + api-key="AIzaSyDTP-eiQezleFsV2WddFBAhF_WEzx_8v_g" + auth-domain="polymerfire-test.firebaseapp.com" + database-url="https://polymerfire-test.firebaseio.com"> + name="alt" + api-key="AIzaSyDTP-eiQezleFsV2WddFBAhF_WEzx_8v_g" + auth-domain="polymerfire-test.firebaseapp.com" + database-url="https://polymerfire-test.firebaseio.com"> + api-key="AIzaSyDTP-eiQezleFsV2WddFBAhF_WEzx_8v_g" + auth-domain="polymerfire-test.firebaseapp.com" + database-url="https://polymerfire-test.firebaseio.com"> diff --git a/test/firebase-database-behavior.html b/test/firebase-database-behavior.html index f3efa47..fe2053b 100644 --- a/test/firebase-database-behavior.html +++ b/test/firebase-database-behavior.html @@ -23,10 +23,10 @@ + name="test" + api-key="AIzaSyDTP-eiQezleFsV2WddFBAhF_WEzx_8v_g" + auth-domain="polymerfire-test.firebaseapp.com" + database-url="https://polymerfire-test.firebaseio.com"> diff --git a/test/firebase-document.html b/test/firebase-document.html index b97adcf..f5979a0 100644 --- a/test/firebase-document.html +++ b/test/firebase-document.html @@ -24,10 +24,10 @@ + name="test" + api-key="AIzaSyDTP-eiQezleFsV2WddFBAhF_WEzx_8v_g" + auth-domain="polymerfire-test.firebaseapp.com" + database-url="https://polymerfire-test.firebaseio.com"> @@ -65,6 +65,59 @@ }); } }); + + function pushFirebaseValue(path, value) { + return firebase.app('test').database().ref(path).push(value); + } + + function clearFirebaseValue(path) { + return firebase.app('test').database().ref(path).set(null); + } + + var makeObject; + var root; + + setup(function() { + var objectId = 0; + makeObject = function(value) { + return { + val: value || objectId++ + }; + }; + + return pushFirebaseValue('/test', { ignore: 'me' }).then(function(snapshot) { + root = '/test/' + snapshot.key; + }); + }); + + suite('exists attribute', function() { + var query; + + setup(function() { + query = fixture('BasicStorage'); + query.path = root + '/list'; + return query.transactionsComplete; + }); + + test('exists is null when we change the path', function() { + query.path = '/myNewPath'; + expect(query.exists).to.be.equal(null); + }); + + test('exists is true when we have data false when we remove it.', function() { + var object = makeObject(); + + return pushFirebaseValue(query.path, object).then(function() { + expect(query.exists).to.be.equal(true); + }).then(function(){ + clearFirebaseValue(query.path); + }).then(function() { + expect(query.exists).to.be.equal(false); + }); + }); + + }); + }); diff --git a/test/firebase-query.html b/test/firebase-query.html index 777e7b5..e0aff54 100644 --- a/test/firebase-query.html +++ b/test/firebase-query.html @@ -21,10 +21,10 @@ + name="test" + api-key="AIzaSyBzKhxNa2k9pA3m9_Ji3POFAKyGGFnyshI" + auth-domain="note-app-firebase-3a483.firebaseapp.com" + database-url="https://note-app-firebase-3a483.firebaseio.com"> @@ -176,6 +176,7 @@ var object = makeObject(); return pushFirebaseValue(query.path, object).then(function() { + expect(query.exists).to.be.equal(true); expect(query.data.length).to.be.equal(1); expect(query.data[0]).to.be.ok; expect(query.data[0].val).to.be.equal(object.val); @@ -241,6 +242,22 @@ expect(query.data[0].foo).to.be.eql(undefined); }); }); + + test('exists is null when template is stamped', function() { + expect(query.exists).to.be.equal(null); + }) + + test('exists is true when we have data false when we remove it.', function() { + var object = makeObject(); + + return pushFirebaseValue(query.path, object).then(function() { + expect(query.exists).to.be.equal(true); + }).then(function(){ + clearFirebaseValue(query.path); + }).then(function() { + expect(query.exists).to.be.equal(false); + }); + }); }); suite('querying against leaf node collections', function() {