Skip to content

Commit aefb30e

Browse files
authored
Merge branch 'master' into patch-1
2 parents 3cee34f + 10afd64 commit aefb30e

33 files changed

+395
-336
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
<a name="5.0.0-rc.3"></a>
2+
# [5.0.0-rc.3](https://github.com/angular/angularfire2/compare/2.0.0-beta.8...5.0.0-rc.3) (2017-10-14)
3+
4+
5+
### Bug Fixes
6+
7+
* **afs:** change doc.update() parameter type to Partial<T> ([#1247](https://github.com/angular/angularfire2/issues/1247)) ([297cabb](https://github.com/angular/angularfire2/commit/297cabb)), closes [#1245](https://github.com/angular/angularfire2/issues/1245) [#1215](https://github.com/angular/angularfire2/issues/1215)
8+
* **rtdb:** Fixed null set handling, ordering, and cleaned up types ([#1264](https://github.com/angular/angularfire2/issues/1264)) ([eda1c41](https://github.com/angular/angularfire2/commit/eda1c41))
9+
10+
111
<a name="5.0.0-rc.2"></a>
212
# [5.0.0-rc.2](https://github.com/angular/angularfire2/compare/5.0.0-rc.0...5.0.0-rc.2) (2017-10-05)
313

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Status: Release candidate
2222

2323
[Upgrading to v5.0? Check out our guide.](docs/version-5-upgrade.md)
2424

25+
**Having troubles?** Get help on the [Firebase Mailing List](https://groups.google.com/forum/#!forum/firebase-talk) (offically supported), the [Firebase Community Slack](https://firebase.community/) (look for the `#angularfire2` room), [Gitter](https://gitter.im/angular/angularfire2), or [Stack Overflow](https://stackoverflow.com/questions/tagged/angularfire2).
26+
2527
## Install
2628

2729
```bash

docs/ionic/v3.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ import { MyApp } from './app.component';
195195
import { HomePage } from '../pages/home/home';
196196

197197
import { AngularFireModule } from 'angularfire2';
198-
import { AngularFireDatabaseModule } from 'angularfire2/database';
198+
import { AngularFireDatabaseModule, AngularFireDatabase } from 'angularfire2/database';
199199
import { AngularFireAuthModule } from 'angularfire2/auth';
200200

201201
export const firebaseConfig = {

docs/rtdb/lists.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,16 @@ itemsRef.remove();
204204
import { Component } from '@angular/core';
205205
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
206206
import { Observable } from 'rxjs/Observable';
207+
import 'rxjs/add/operator/map';
207208

208209
@Component({
209210
selector: 'app-root',
210211
template: `
211212
<ul>
212213
<li *ngFor="let item of items | async">
213214
<input type="text" #updatetext [value]="item.text" />
214-
<button (click)="updateItem(item.$key, updatetext.value)">Update</button>
215-
<button (click)="deleteItem(item.$key)">Delete</button>
215+
<button (click)="updateItem(item.key, updatetext.value)">Update</button>
216+
<button (click)="deleteItem(item.key)">Delete</button>
216217
</li>
217218
</ul>
218219
<input type="text" #newitem />
@@ -225,7 +226,10 @@ export class AppComponent {
225226
items: Observable<any[]>;
226227
constructor(db: AngularFireDatabase) {
227228
this.itemsRef = db.list('messages');
228-
this.items = this.itemsRef.valueChanges();
229+
// Use snapshotChanges().map() to store the key
230+
this.items = this.itemsRef.snapshotChanges().map(changes => {
231+
return changes.map(c => ({ key: c.payload.key, ...c.payload.val() }));
232+
});
229233
}
230234
addItem(newName: string) {
231235
this.itemsRef.push({ text: newName });

docs/rtdb/objects.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ AngularFire unwraps the Firebase DataSnapshot by default, but you can get the da
173173
this.itemRef = db.object('item');
174174
this.itemRef.snapshotChanges().subscribe(action => {
175175
console.log(action.type);
176-
console.log(action.snapshot.key)
177-
console.log(action.snapshot.val())
176+
console.log(action.key)
177+
console.log(action.payload.val())
178178
});
179179
```
180180

docs/rtdb/querying-lists.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,32 +86,39 @@ import 'rxjs/add/operator/switchMap';
8686
@Component({
8787
selector: 'app-root',
8888
template: `
89-
<ul>
90-
<li *ngFor="let item of items | async">
91-
{{ item.text }}
92-
</li>
93-
</ul>
89+
<h1>Firebase widgets!</h1>
90+
<div *ngIf="items$ | async; let items; else loading">
91+
<ul>
92+
<li *ngFor="let item of items">
93+
{{ item.payload.val().text }}
94+
<code>{{ item.payload.key }}</code>
95+
</li>
96+
</ul>
97+
<div *ngIf="items.length === 0">No results, try clearing filters</div>
98+
</div>
99+
<ng-template #loading>Loading&hellip;</ng-template>
94100
<div>
95101
<h4>Filter by size</h4>
96102
<button (click)="filterBy('small')">Small</button>
97103
<button (click)="filterBy('medium')">Medium</button>
98104
<button (click)="filterBy('large')">Large</button>
105+
<button (click)="filterBy('x-large')">Extra Large</button>
99106
<button (click)="filterBy(null)" *ngIf="this.size$.getValue()">
100107
<em>clear filter</em>
101108
</button>
102109
</div>
103110
`,
104111
})
105112
export class AppComponent {
106-
items: Observable<AngularFireAction<firebase.database.DataSnapshot>[]>;
113+
items$: Observable<AngularFireAction<firebase.database.DataSnapshot>[]>;
107114
size$: BehaviorSubject<string|null>;
108115

109116
constructor(db: AngularFireDatabase) {
110117
this.size$ = new BehaviorSubject(null);
111-
this.items = this.size$.switchMap(size =>
118+
this.items$ = this.size$.switchMap(size =>
112119
db.list('/items', ref =>
113120
size ? ref.orderByChild('size').equalTo(size) : ref
114-
).valueChanges();
121+
).snapshotChanges();
115122
);
116123
}
117124
filterBy(size: string|null) {

docs/version-5-upgrade.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,20 @@ Calling `.valueChanges()` returns an Observable without any metadata. If you are
3434
### 4.0
3535
```ts
3636
constructor(afDb: AngularFireDatabase) {
37-
afDb.object('items/1').subscribe(item => console.log(item.$key));
37+
afDb.list('items').subscribe(items => {
38+
const allKeys = items.map(item => item.$key);
39+
});
3840
}
3941
```
4042

4143
### 5.0
4244
```ts
4345
constructor(afDb: AngularFireDatabase) {
4446
afDb.list('items').snapshotChanges().map(actions => {
45-
return actions.map(action => ({ $key: action.key, ...action.payload.val() }));
46-
}).subscribe(items => items.forEach(item => console.log(item.$key)));
47+
return actions.map(action => ({ key: action.key, ...action.payload.val() }));
48+
}).subscribe(items => {
49+
return items.map(item => item.key);
50+
});
4751
}
4852
```
4953

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angularfire2",
3-
"version": "5.0.0-rc.2",
3+
"version": "5.0.0-rc.3",
44
"description": "The official library of Firebase and Angular.",
55
"private": true,
66
"scripts": {

src/database/database.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
22
import { database } from 'firebase/app';
33
import 'firebase/database';
44
import { FirebaseApp } from 'angularfire2';
5-
import { PathReference, DatabaseQuery, DatabaseReference, DatabaseSnapshot, ChildEvent, ListenEvent, SnapshotChange, QueryFn, AngularFireList, AngularFireObject } from './interfaces';
5+
import { PathReference, DatabaseQuery, DatabaseReference, DatabaseSnapshot, ChildEvent, ListenEvent, QueryFn, AngularFireList, AngularFireObject } from './interfaces';
66
import { getRef } from './utils';
77
import { createListReference } from './list/create-reference';
88
import { createObjectReference } from './object/create-reference';
@@ -41,8 +41,7 @@ export {
4141
DatabaseReference,
4242
DatabaseSnapshot,
4343
ChildEvent,
44-
ListenEvent,
45-
SnapshotChange,
44+
ListenEvent,
4645
QueryFn,
4746
AngularFireList,
4847
AngularFireObject,

src/database/interfaces.ts

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,47 @@ export type FirebaseOperation = string | firebase.database.Reference | firebase.
55

66
export interface AngularFireList<T> {
77
query: DatabaseQuery;
8-
valueChanges<T>(events?: ChildEvent[]): Observable<T[]>;
8+
valueChanges(events?: ChildEvent[]): Observable<T[]>;
99
snapshotChanges(events?: ChildEvent[]): Observable<SnapshotAction[]>;
1010
stateChanges(events?: ChildEvent[]): Observable<SnapshotAction>;
1111
auditTrail(events?: ChildEvent[]): Observable<SnapshotAction[]>;
1212
update(item: FirebaseOperation, data: T): Promise<void>;
1313
set(item: FirebaseOperation, data: T): Promise<void>;
1414
push(data: T): firebase.database.ThenableReference;
15-
remove(item?: FirebaseOperation): Promise<any>;
15+
remove(item?: FirebaseOperation): Promise<void>;
1616
}
1717

1818
export interface AngularFireObject<T> {
1919
query: DatabaseQuery;
20-
valueChanges<T>(): Observable<T | null>;
21-
snapshotChanges<T>(): Observable<SnapshotAction>;
22-
update(data: T): Promise<any>;
20+
valueChanges(): Observable<T | null>;
21+
snapshotChanges(): Observable<SnapshotAction>;
22+
update(data: Partial<T>): Promise<void>;
2323
set(data: T): Promise<void>;
24-
remove(): Promise<any>;
24+
remove(): Promise<void>;
2525
}
2626

2727
export interface FirebaseOperationCases {
28-
stringCase: () => Promise<void | any>;
29-
firebaseCase?: () => Promise<void | any>;
30-
snapshotCase?: () => Promise<void | any>;
31-
unwrappedSnapshotCase?: () => Promise<void | any>;
28+
stringCase: () => Promise<void>;
29+
firebaseCase?: () => Promise<void>;
30+
snapshotCase?: () => Promise<void>;
31+
unwrappedSnapshotCase?: () => Promise<void>;
3232
}
3333

3434
export type QueryFn = (ref: DatabaseReference) => DatabaseQuery;
3535
export type ChildEvent = 'child_added' | 'child_removed' | 'child_changed' | 'child_moved';
3636
export type ListenEvent = 'value' | ChildEvent;
3737

38-
export type SnapshotChange = {
39-
event: string;
40-
snapshot: DatabaseSnapshot | null;
41-
prevKey: string | undefined;
42-
}
43-
4438
export interface Action<T> {
45-
type: string;
39+
type: ListenEvent;
4640
payload: T;
4741
};
4842

4943
export interface AngularFireAction<T> extends Action<T> {
50-
prevKey: string | undefined;
44+
prevKey: string | null | undefined;
5145
key: string | null;
5246
}
5347

54-
export interface SnapshotPrevKey {
55-
snapshot: DatabaseSnapshot | null;
56-
prevKey: string | undefined;
57-
}
58-
59-
export type SnapshotAction = AngularFireAction<DatabaseSnapshot | null>;
48+
export type SnapshotAction = AngularFireAction<DatabaseSnapshot>;
6049

6150
export type Primitive = number | string | boolean;
6251

src/database/list/audit-trail.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'rxjs/add/operator/skip';
99
const rando = () => (Math.random() + 1).toString(36).substring(7);
1010
const FIREBASE_APP_NAME = rando();
1111

12-
describe('stateChanges', () => {
12+
describe('auditTrail', () => {
1313
let app: FirebaseApp;
1414
let db: AngularFireDatabase;
1515
let createRef: (path: string) => firebase.database.Reference;
@@ -56,7 +56,7 @@ describe('stateChanges', () => {
5656

5757
const { changes } = prepareAuditTrail();
5858
changes.subscribe(actions => {
59-
const data = actions.map(a => a.payload!.val());
59+
const data = actions.map(a => a.payload.val());
6060
expect(data).toEqual(items);
6161
done();
6262
});

src/database/list/audit-trail.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { DatabaseQuery, ChildEvent, AngularFireAction, SnapshotAction } from '../interfaces';
1+
import { DatabaseQuery, ChildEvent, DatabaseSnapshot, AngularFireAction, SnapshotAction } from '../interfaces';
22
import { stateChanges } from './state-changes';
3-
import { waitForLoaded } from './loaded';
43
import { Observable } from 'rxjs/Observable';
54
import { database } from 'firebase/app';
5+
import { fromRef } from '../observable/fromRef';
6+
7+
68
import 'rxjs/add/operator/skipWhile';
79
import 'rxjs/add/operator/withLatestFrom';
810
import 'rxjs/add/operator/map';
@@ -16,3 +18,47 @@ export function auditTrail(query: DatabaseQuery, events?: ChildEvent[]): Observa
1618
.scan((current, action) => [...current, action], []);
1719
return waitForLoaded(query, auditTrail$);
1820
}
21+
22+
interface LoadedMetadata {
23+
data: AngularFireAction<database.DataSnapshot>;
24+
lastKeyToLoad: any;
25+
}
26+
27+
function loadedData(query: DatabaseQuery): Observable<LoadedMetadata> {
28+
// Create an observable of loaded values to retrieve the
29+
// known dataset. This will allow us to know what key to
30+
// emit the "whole" array at when listening for child events.
31+
return fromRef(query, 'value')
32+
.map(data => {
33+
// Store the last key in the data set
34+
let lastKeyToLoad;
35+
// Loop through loaded dataset to find the last key
36+
data.payload.forEach(child => {
37+
lastKeyToLoad = child.key; return false;
38+
});
39+
// return data set and the current last key loaded
40+
return { data, lastKeyToLoad };
41+
});
42+
}
43+
44+
function waitForLoaded(query: DatabaseQuery, action$: Observable<SnapshotAction[]>) {
45+
const loaded$ = loadedData(query);
46+
return loaded$
47+
.withLatestFrom(action$)
48+
// Get the latest values from the "loaded" and "child" datasets
49+
// We can use both datasets to form an array of the latest values.
50+
.map(([loaded, actions]) => {
51+
// Store the last key in the data set
52+
let lastKeyToLoad = loaded.lastKeyToLoad;
53+
// Store all child keys loaded at this point
54+
const loadedKeys = actions.map(snap => snap.key);
55+
return { actions, lastKeyToLoad, loadedKeys }
56+
})
57+
// This is the magical part, only emit when the last load key
58+
// in the dataset has been loaded by a child event. At this point
59+
// we can assume the dataset is "whole".
60+
.skipWhile(meta => meta.loadedKeys.indexOf(meta.lastKeyToLoad) === -1)
61+
// Pluck off the meta data because the user only cares
62+
// to iterate through the snapshots
63+
.map(meta => meta.actions);
64+
}

0 commit comments

Comments
 (0)