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-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/test/firebase-document.html b/test/firebase-document.html index b97adcf..3fb00e8 100644 --- a/test/firebase-document.html +++ b/test/firebase-document.html @@ -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..fb9e059 100644 --- a/test/firebase-query.html +++ b/test/firebase-query.html @@ -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() {