Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

Commit bfbb043

Browse files
committed
Merge branch 'master' into initial-null-value-bug
Conflicts: src/FirebaseObject.js
2 parents 2e0b0cc + c485405 commit bfbb043

File tree

11 files changed

+121
-80
lines changed

11 files changed

+121
-80
lines changed

bower.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
"firebase": "2.1.x"
3535
},
3636
"devDependencies": {
37-
"lodash": "~2.4.1",
38-
"angular-mocks": "~1.2.18",
39-
"mockfirebase": "~0.7.0"
37+
"angular-mocks": "~1.3.11",
38+
"mockfirebase": "~0.8.0"
4039
}
4140
}

package.json

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,30 @@
3535
"firebase": "2.1.x"
3636
},
3737
"devDependencies": {
38-
"coveralls": "^2.11.1",
39-
"grunt": "~0.4.1",
38+
"coveralls": "^2.11.2",
39+
"grunt": "~0.4.5",
4040
"grunt-cli": "^0.1.13",
41-
"grunt-contrib-concat": "^0.4.0",
42-
"grunt-contrib-connect": "^0.7.1",
43-
"grunt-contrib-jshint": "~0.10.0",
44-
"grunt-contrib-uglify": "~0.2.2",
45-
"grunt-contrib-watch": "~0.5.1",
46-
"grunt-karma": "~0.8.3",
47-
"grunt-notify": "~0.2.7",
48-
"grunt-protractor-runner": "^1.0.0",
49-
"grunt-shell-spawn": "^0.3.0",
50-
"jasmine-spec-reporter": "^0.4.0",
51-
"karma": "~0.12.0",
52-
"karma-chrome-launcher": "^0.1.4",
53-
"karma-coverage": "^0.2.4",
54-
"karma-failed-reporter": "0.0.2",
41+
"grunt-contrib-concat": "^0.5.0",
42+
"grunt-contrib-connect": "^0.9.0",
43+
"grunt-contrib-jshint": "^0.11.0",
44+
"grunt-contrib-uglify": "^0.7.0",
45+
"grunt-contrib-watch": "^0.6.1",
46+
"grunt-karma": "^0.10.1",
47+
"grunt-notify": "^0.4.1",
48+
"grunt-protractor-runner": "^1.2.1",
49+
"grunt-shell-spawn": "^0.3.1",
50+
"jasmine-core": "^2.1.3",
51+
"jasmine-spec-reporter": "^2.1.0",
52+
"karma": "~0.12.31",
53+
"karma-chrome-launcher": "^0.1.7",
54+
"karma-coverage": "^0.2.7",
55+
"karma-failed-reporter": "0.0.3",
5556
"karma-html2js-preprocessor": "~0.1.0",
56-
"karma-jasmine": "~0.2.0",
57-
"karma-phantomjs-launcher": "~0.1.0",
58-
"karma-sauce-launcher": "~0.2.9",
59-
"karma-spec-reporter": "0.0.13",
60-
"load-grunt-tasks": "~0.2.0",
61-
"protractor": "^1.0.0"
57+
"karma-jasmine": "^0.3.5",
58+
"karma-phantomjs-launcher": "~0.1.4",
59+
"karma-sauce-launcher": "~0.2.10",
60+
"karma-spec-reporter": "0.0.16",
61+
"load-grunt-tasks": "^3.1.0",
62+
"protractor": "^1.6.1"
6263
}
6364
}

src/FirebaseArray.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@
210210
$loaded: function(resolve, reject) {
211211
var promise = this._promise;
212212
if( arguments.length ) {
213+
// allow this method to be called just like .then
214+
// by passing any arguments on to .then
213215
promise = promise.then.call(promise, resolve, reject);
214216
}
215217
return promise;

src/FirebaseObject.js

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -318,64 +318,54 @@
318318
self.scope = scope;
319319
self.varName = varName;
320320

321-
function equals(rec) {
322-
var parsed = getScope();
323-
var newData = $firebaseUtils.scopeData(rec);
324-
return angular.equals(parsed, newData) &&
325-
parsed.$priority === rec.$priority &&
326-
parsed.$value === rec.$value;
327-
}
328-
329-
function getScope() {
330-
return $firebaseUtils.scopeData(parsed(scope));
321+
function equals(scopeValue) {
322+
return angular.equals(scopeValue, rec) &&
323+
scopeValue.$priority === rec.$priority &&
324+
scopeValue.$value === rec.$value;
331325
}
332326

333327
function setScope(rec) {
334328
parsed.assign(scope, $firebaseUtils.scopeData(rec));
335329
}
336330

337-
var send = $firebaseUtils.debounce(function() {
338-
var scopeData = getScope();
339-
rec.$$scopeUpdated(scopeData)
340-
['finally'](function() {
341-
sending = false;
342-
if(!scopeData.hasOwnProperty('$value')){
343-
delete rec.$value;
344-
delete parsed(scope).$value;
345-
}
331+
var send = $firebaseUtils.debounce(function(val) {
332+
rec.$$scopeUpdated($firebaseUtils.scopeData(val))
333+
['finally'](function() {
334+
sending = false;
335+
if(!scopeData.hasOwnProperty('$value')){
336+
delete rec.$value;
337+
delete parsed(scope).$value;
346338
}
339+
}
347340
);
348341
}, 50, 500);
349342

350-
var scopeUpdated = function() {
351-
if( !equals(rec) ) {
343+
var scopeUpdated = function(newVal) {
344+
newVal = newVal[0];
345+
if( !equals(newVal) ) {
352346
sending = true;
353-
send();
347+
send(newVal);
354348
}
355349
};
356350

357351
var recUpdated = function() {
358-
if( !sending && !equals(rec) ) {
352+
if( !sending && !equals(parsed(scope)) ) {
359353
setScope(rec);
360354
}
361355
};
362356

363357
// $watch will not check any vars prefixed with $, so we
364358
// manually check $priority and $value using this method
365-
function checkMetaVars() {
366-
var dat = parsed(scope);
367-
if( dat.$value !== rec.$value || dat.$priority !== rec.$priority ) {
368-
scopeUpdated();
369-
}
359+
function watchExp(){
360+
var obj = parsed(scope);
361+
return [obj, obj.$priority, obj.$value];
370362
}
371363

372-
self.subs.push(scope.$watch(checkMetaVars));
373-
374364
setScope(rec);
375365
self.subs.push(scope.$on('$destroy', self.unbind.bind(self)));
376366

377367
// monitor scope for any changes
378-
self.subs.push(scope.$watch(varName, scopeUpdated, true));
368+
self.subs.push(scope.$watch(watchExp, scopeUpdated, true));
379369

380370
// monitor the object for changes
381371
self.subs.push(rec.$watch(recUpdated));

src/firebase.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
//
1010
// * `ref`: A Firebase reference. Queries or limits may be applied.
1111
// * `config`: An object containing any of the advanced config options explained in API docs
12-
.factory("$firebase", [ "$firebaseUtils", "$firebaseConfig",
13-
function ($firebaseUtils, $firebaseConfig) {
12+
.factory("$firebase", [ "$log", "$firebaseUtils", "$firebaseConfig",
13+
function ($log, $firebaseUtils, $firebaseConfig) {
1414
function AngularFire(ref, config) {
1515
// make the new keyword optional
1616
if (!(this instanceof AngularFire)) {
@@ -52,7 +52,7 @@
5252
}
5353
if( angular.isFunction(ref.set) || !angular.isObject(data) ) {
5454
// this is not a query, just do a flat set
55-
ref.ref().set(data, this._handle(def, ref));
55+
ref.set(data, this._handle(def, ref));
5656
}
5757
else {
5858
var dataCopy = angular.extend({}, data);
@@ -202,7 +202,13 @@
202202
ref.on('child_removed', removed, error);
203203

204204
// determine when initial load is completed
205-
ref.once('value', function() { resolve(null); }, resolve);
205+
ref.once('value', function(snap) {
206+
if (angular.isArray(snap.val())) {
207+
$log.warn('Storing data using array indices in Firebase can result in unexpected behavior. See https://www.firebase.com/docs/web/guide/understanding-data.html#section-arrays-in-firebase for more information.');
208+
}
209+
210+
resolve(null);
211+
}, resolve);
206212
}
207213

208214
// call resolve(), do not call this directly
@@ -281,7 +287,13 @@
281287

282288
function init() {
283289
ref.on('value', applyUpdate, error);
284-
ref.once('value', function() { resolve(null); }, resolve);
290+
ref.once('value', function(snap) {
291+
if (angular.isArray(snap.val())) {
292+
$log.warn('Storing data using array indices in Firebase can result in unexpected behavior. See https://www.firebase.com/docs/web/guide/understanding-data.html#section-arrays-in-firebase for more information.');
293+
}
294+
295+
resolve(null);
296+
}, resolve);
285297
}
286298

287299
// call resolve(); do not call this directly

src/utils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,12 @@
430430
});
431431
return dat;
432432
},
433+
434+
/**
435+
* AngularFire version number.
436+
*/
437+
VERSION: '0.0.0',
438+
433439
batchDelay: firebaseBatchDelay,
434440
allPromises: $q.all.bind($q)
435441
};

tests/protractor/chat/chat.spec.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ var protractor = require('protractor');
22
var Firebase = require('firebase');
33

44
describe('Chat App', function () {
5-
// Protractor instance
6-
var ptor = protractor.getInstance();
7-
85
// Reference to the Firebase which stores the data for this demo
96
var firebaseRef = new Firebase('https://angularFireTests.firebaseio-demo.com/chat');
107

@@ -148,4 +145,4 @@ describe('Chat App', function () {
148145
expect(messages.count()).toBe(0);
149146
expect(messagesCount.getText()).toEqual('0');
150147
});
151-
});
148+
});

tests/travis.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#!/bin/bash
2+
set -e
13
grunt build
24
grunt test:unit
35
if [ $TRAVIS_TAG ]; then

tests/unit/FirebaseObject.spec.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,7 @@ describe('$FirebaseObject', function() {
346346
$scope.test.$priority = 999;
347347
});
348348
$interval.flush(500);
349-
$timeout.flush(); // for $interval
350-
$timeout.flush(); // for $watch
349+
$timeout.flush();
351350
expect(spy).toHaveBeenCalledWith(jasmine.objectContaining({'.priority': 999}));
352351
});
353352

@@ -363,11 +362,39 @@ describe('$FirebaseObject', function() {
363362
$scope.test.$value = 'bar';
364363
});
365364
$interval.flush(500);
366-
$timeout.flush(); // for $interval
367-
$timeout.flush(); // for $watch
365+
$timeout.flush();
368366
expect(spy).toHaveBeenCalledWith(jasmine.objectContaining({'.value': 'bar'}));
369367
});
370368

369+
it('should only call $$scopeUpdated once if both metaVars and properties change in the same $digest',function(){
370+
var $scope = $rootScope.$new();
371+
var fb = new MockFirebase();
372+
fb.autoFlush(true);
373+
fb.setWithPriority({text:'hello'},3);
374+
var $fb = new $firebase(fb);
375+
var obj = $fb.$asObject();
376+
flushAll();
377+
flushAll();
378+
obj.$bindTo($scope, 'test');
379+
$scope.$apply();
380+
expect($scope.test).toEqual({text:'hello', $id: obj.$id, $priority: 3});
381+
var callCount = 0;
382+
var old$scopeUpdated = obj.$$scopeUpdated;
383+
obj.$$scopeUpdated = function(){
384+
callCount++;
385+
return old$scopeUpdated.apply(this,arguments);
386+
};
387+
$scope.$apply(function(){
388+
$scope.test.text='goodbye';
389+
$scope.test.$priority=4;
390+
});
391+
flushAll();
392+
flushAll();
393+
flushAll();
394+
flushAll();
395+
expect(callCount).toEqual(1);
396+
});
397+
371398
it('should throw error if double bound', function() {
372399
var $scope = $rootScope.$new();
373400
var aSpy = jasmine.createSpy('firstBind');

tests/unit/firebase.spec.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,11 @@ describe('$firebase', function () {
136136
it('should reject if fails', function() {
137137
var whiteSpy = jasmine.createSpy('resolve');
138138
var blackSpy = jasmine.createSpy('reject');
139-
$fb.$ref().failNext('push', 'failpush');
139+
$fb.$ref().failNext('push', new Error('failpush'));
140140
$fb.$push({foo: 'bar'}).then(whiteSpy, blackSpy);
141141
flushAll();
142142
expect(whiteSpy).not.toHaveBeenCalled();
143-
expect(blackSpy).toHaveBeenCalledWith('failpush');
143+
expect(blackSpy).toHaveBeenCalledWith(new Error('failpush'));
144144
});
145145

146146
it('should save correct data into Firebase', function() {
@@ -206,13 +206,13 @@ describe('$firebase', function () {
206206
});
207207

208208
it('should reject if fails', function() {
209-
$fb.$ref().failNext('set', 'setfail');
209+
$fb.$ref().failNext('set', new Error('setfail'));
210210
var whiteSpy = jasmine.createSpy('resolve');
211211
var blackSpy = jasmine.createSpy('reject');
212212
$fb.$set({foo: 'bar'}).then(whiteSpy, blackSpy);
213213
flushAll();
214214
expect(whiteSpy).not.toHaveBeenCalled();
215-
expect(blackSpy).toHaveBeenCalledWith('setfail');
215+
expect(blackSpy).toHaveBeenCalledWith(new Error('setfail'));
216216
});
217217

218218
it('should affect query keys only if query used', function() {
@@ -285,11 +285,11 @@ describe('$firebase', function () {
285285
it('should reject if fails', function() {
286286
var whiteSpy = jasmine.createSpy('resolve');
287287
var blackSpy = jasmine.createSpy('reject');
288-
$fb.$ref().failNext('remove', 'test_fail_remove');
288+
$fb.$ref().failNext('remove', new Error('test_fail_remove'));
289289
$fb.$remove().then(whiteSpy, blackSpy);
290290
flushAll();
291291
expect(whiteSpy).not.toHaveBeenCalled();
292-
expect(blackSpy).toHaveBeenCalledWith('test_fail_remove');
292+
expect(blackSpy).toHaveBeenCalledWith(new Error('test_fail_remove'));
293293
});
294294

295295
it('should remove data in Firebase', function() {
@@ -371,11 +371,11 @@ describe('$firebase', function () {
371371
it('should reject if failed', function() {
372372
var whiteSpy = jasmine.createSpy('resolve');
373373
var blackSpy = jasmine.createSpy('reject');
374-
$fb.$ref().failNext('update', 'oops');
374+
$fb.$ref().failNext('update', new Error('oops'));
375375
$fb.$update({index: {foo: 'bar'}}).then(whiteSpy, blackSpy);
376376
flushAll();
377377
expect(whiteSpy).not.toHaveBeenCalled();
378-
expect(blackSpy).toHaveBeenCalled();
378+
expect(blackSpy).toHaveBeenCalledWith(new Error('oops'));
379379
});
380380

381381
it('should not destroy untouched keys', function() {
@@ -435,11 +435,11 @@ describe('$firebase', function () {
435435
it('should reject if failed', function() {
436436
var whiteSpy = jasmine.createSpy('success');
437437
var blackSpy = jasmine.createSpy('failed');
438-
$fb.$ref().child('a').failNext('transaction', 'test_fail');
438+
$fb.$ref().child('a').failNext('transaction', new Error('test_fail'));
439439
$fb.$transaction('a', function() { return true; }).then(whiteSpy, blackSpy);
440440
flushAll();
441441
expect(whiteSpy).not.toHaveBeenCalled();
442-
expect(blackSpy).toHaveBeenCalledWith('test_fail');
442+
expect(blackSpy).toHaveBeenCalledWith(new Error('test_fail'));
443443
});
444444

445445
it('should modify data in firebase', function() {

0 commit comments

Comments
 (0)