Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit fb8c632

Browse files
Merge pull request #1176 from KkevinLi/firestore-onsnapshot
Firestore onSnapshot update to support onError Callbacks.
2 parents 8bbd128 + 156b92f commit fb8c632

File tree

4 files changed

+117
-42
lines changed

4 files changed

+117
-42
lines changed

docs/FIRESTORE.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@ const unsubscribe = citiesCollection.onSnapshot((snapshot: firestore.QuerySnapsh
6060

6161
// then after a while, to detach the listener:
6262
unsubscribe();
63+
64+
/**
65+
* If you pass in SnapshotOptions for the first parameter then your next should be onNext and
66+
* onError if you want for the third parameter. If you pass onNext as the first parameter the
67+
* second will be interpreted as onError callback. Note that you could pass onComplete, but
68+
* it will never be called as stated by Firestore docs.
69+
*
70+
* onError callbacks are optional!
71+
* onSnapshot(p1: SnapshotListenOptions|onNextCallback, p2?: onNextCallback | onErrorCallback, p3?: onErrorCallback?)
72+
*/
73+
const docRef: firestore.DocumentReference = firebase.firestore().collection("cities").doc("SF");
74+
docRef.onSnapshot(
75+
{includeMetadataChanges: true}, // Comment out if you just want onNext && onError callbacks
76+
(doc: firestore.DocumentSnapshot) => {
77+
78+
const source = doc.metadata.fromCache ? "local cache" : "server";
79+
console.log("Data came from " + source);
80+
console.log("Has pending writes? " + doc.metadata.hasPendingWrites);
81+
},
82+
(error: Error) => {
83+
console.error(error);
84+
}
85+
);
6386
```
6487

6588
> Using **Observables**? [Check the example in the demo app](https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/f6972433dea48bf1d342a6e4ef7f955dff341837/demo-ng/app/item/items.component.ts#L187-L198).

src/firebase.android.ts

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,46 +2272,66 @@ firebase.firestore.collection = (collectionPath: string): firestore.CollectionRe
22722272
}
22732273
};
22742274

2275-
firebase.firestore.onDocumentSnapshot = (docRef: com.google.firebase.firestore.DocumentReference, optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callback: (doc: DocumentSnapshot) => void): () => void => {
2275+
firebase.firestore.onDocumentSnapshot = (docRef: com.google.firebase.firestore.DocumentReference, optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callbackOrOnError: (docOrError: DocumentSnapshot | Error) => void, onError: (error: Error) => void): () => void => {
22762276
let options = com.google.firebase.firestore.MetadataChanges.EXCLUDE;
2277+
let onNextCallback: (snapshot: DocumentSnapshot) => void;
2278+
let onErrorCallback: (error: Error) => void;
2279+
22772280
if ((typeof optionsOrCallback) === "function") {
2278-
callback = <(snapshot: DocumentSnapshot) => void>optionsOrCallback;
2279-
} else if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges) {
2281+
onNextCallback = <(snapshot: DocumentSnapshot) => void>optionsOrCallback;
2282+
onErrorCallback = callbackOrOnError;
2283+
} else {
2284+
onNextCallback = callbackOrOnError;
2285+
onErrorCallback = onError;
2286+
}
2287+
if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges) {
22802288
options = com.google.firebase.firestore.MetadataChanges.INCLUDE;
22812289
}
22822290

22832291
const listener = docRef.addSnapshotListener(options, new com.google.firebase.firestore.EventListener({
2284-
onEvent: ((snapshot: com.google.firebase.firestore.DocumentSnapshot, exception: com.google.firebase.firestore.FirebaseFirestoreException) => {
2285-
if (exception === null) {
2286-
callback(new DocumentSnapshot(snapshot));
2287-
}
2288-
})
2289-
})
2292+
onEvent: ((snapshot: com.google.firebase.firestore.DocumentSnapshot, exception: com.google.firebase.firestore.FirebaseFirestoreException) => {
2293+
if (exception !== null) {
2294+
const error = "onDocumentSnapshot error code: " + exception.getCode();
2295+
onErrorCallback && onErrorCallback(new Error(error));
2296+
return;
2297+
}
2298+
onNextCallback && onNextCallback(new DocumentSnapshot(snapshot));
2299+
})
2300+
})
22902301
);
22912302

22922303
return () => listener.remove();
22932304
};
22942305

2295-
firebase.firestore.onCollectionSnapshot = (colRef: com.google.firebase.firestore.CollectionReference, optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callback: (snapshot: QuerySnapshot) => void): () => void => {
2306+
firebase.firestore.onCollectionSnapshot = (colRef: com.google.firebase.firestore.CollectionReference, optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callbackOrOnError: (snapshotOrError: QuerySnapshot | Error) => void, onError?: (error: Error) => void): () => void => {
22962307
let options = com.google.firebase.firestore.MetadataChanges.EXCLUDE;
2308+
let onNextCallback: (snapshot: QuerySnapshot) => void;
2309+
let onErrorCallback: (error: Error) => void;
2310+
2311+
// If we passed in an onNext for the first parameter, the next parameter would be onError if provided
2312+
// If options was the first parameter then the next parameter would be onNext if provided
22972313
if ((typeof optionsOrCallback) === "function") {
2298-
callback = <(snapshot: QuerySnapshot) => void>optionsOrCallback;
2299-
} else if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges) {
2314+
onNextCallback = <(snapshot: QuerySnapshot) => void>optionsOrCallback;
2315+
onErrorCallback = callbackOrOnError;
2316+
} else {
2317+
onNextCallback = callbackOrOnError; // Can be undefined if callback was not provided
2318+
onErrorCallback = onError; // Can be undefined if onError was not provided
2319+
}
2320+
if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges) {
23002321
options = com.google.firebase.firestore.MetadataChanges.INCLUDE;
23012322
}
23022323

23032324
const listener = colRef.addSnapshotListener(options, new com.google.firebase.firestore.EventListener({
2304-
onEvent: ((snapshot: com.google.firebase.firestore.QuerySnapshot, exception: com.google.firebase.firestore.FirebaseFirestoreException) => {
2305-
if (exception !== null) {
2306-
console.error('onCollectionSnapshot error code: ' + exception.getCode());
2307-
return;
2308-
}
2309-
2310-
callback(new QuerySnapshot(snapshot));
2311-
})
2312-
})
2325+
onEvent: ((snapshot: com.google.firebase.firestore.QuerySnapshot, exception: com.google.firebase.firestore.FirebaseFirestoreException) => {
2326+
if (exception !== null) {
2327+
const error = "onCollectionSnapshot error code: " + exception.getCode();
2328+
onErrorCallback && onErrorCallback(new Error(error));
2329+
return;
2330+
}
2331+
onNextCallback && onNextCallback(new QuerySnapshot(snapshot));
2332+
})
2333+
})
23132334
);
2314-
23152335
return () => listener.remove();
23162336
};
23172337

@@ -2332,7 +2352,7 @@ firebase.firestore._getDocumentReference = (docRef?: JDocumentReference): firest
23322352
get: () => firebase.firestore.getDocument(collectionPath, docRef.getId()),
23332353
update: (data: any) => firebase.firestore.update(collectionPath, docRef.getId(), data),
23342354
delete: () => firebase.firestore.delete(collectionPath, docRef.getId()),
2335-
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((doc: DocumentSnapshot) => void), callback: (doc: DocumentSnapshot) => void) => firebase.firestore.onDocumentSnapshot(docRef, optionsOrCallback, callback),
2355+
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callbackOrOnError?: (docOrError: DocumentSnapshot | Error) => void, onError?: (error: Error) => void) => firebase.firestore.onDocumentSnapshot(javaObj, optionsOrCallback, callbackOrOnError, onError),
23362356
android: docRef
23372357
};
23382358
};
@@ -2621,7 +2641,7 @@ firebase.firestore._getQuery = (collectionPath: string, query: com.google.fireba
26212641
where: (fp: string, os: firestore.WhereFilterOp, v: any): firestore.Query => firebase.firestore.where(collectionPath, fp, os, v, query),
26222642
orderBy: (fp: string, directionStr: firestore.OrderByDirection): firestore.Query => firebase.firestore.orderBy(collectionPath, fp, directionStr, query),
26232643
limit: (limit: number): firestore.Query => firebase.firestore.limit(collectionPath, limit, query),
2624-
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callback?: (snapshot: QuerySnapshot) => void) => firebase.firestore.onCollectionSnapshot(query, optionsOrCallback, callback),
2644+
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callbackOrOnError?: (snapshotOrError: QuerySnapshot | Error) => void, onError?: (error: Error) => void) => firebase.firestore.onCollectionSnapshot(query, optionsOrCallback, callbackOrOnError, onError),
26252645
startAfter: (snapshot: DocumentSnapshot) => firebase.firestore.startAfter(collectionPath, snapshot, query),
26262646
startAt: (snapshot: DocumentSnapshot) => firebase.firestore.startAt(collectionPath, snapshot, query),
26272647
endAt: (snapshot: DocumentSnapshot) => firebase.firestore.endAt(collectionPath, snapshot, query),

src/firebase.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,21 +789,30 @@ export namespace firestore {
789789

790790
export interface DocumentReference {
791791
readonly discriminator: "docRef";
792+
792793
readonly id: string;
794+
793795
/**
794796
* A reference to the Collection to which this DocumentReference belongs.
795797
*/
796798
readonly parent: CollectionReference;
799+
797800
readonly path: string;
801+
798802
collection: (collectionPath: string) => CollectionReference;
803+
799804
set: (document: any, options?: SetOptions) => Promise<void>;
805+
800806
get: () => Promise<DocumentSnapshot>;
807+
801808
update: (document: any) => Promise<void>;
809+
802810
delete: () => Promise<void>;
803811

804-
onSnapshot(optionsOrCallback: SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callback?: (snapshot: DocumentSnapshot) => void): () => void;
812+
onSnapshot(optionsOrCallback: SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callbackOrOnError?: (snapshot: DocumentSnapshot | Error) => void, onError?: (error: Error) => void): () => void;
805813

806814
android?: any;
815+
807816
ios?: any;
808817
}
809818

@@ -816,7 +825,7 @@ export namespace firestore {
816825

817826
limit(limit: number): Query;
818827

819-
onSnapshot(optionsOrCallback: SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callback?: (snapshot: QuerySnapshot) => void): () => void;
828+
onSnapshot(optionsOrCallback: SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callbackOrOnError?: (snapshotOrError: QuerySnapshot | Error) => void, onError?: (error: Error) => void): () => void;
820829

821830
startAt(snapshot: DocumentSnapshot): Query;
822831

src/firebase.ios.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,53 +1924,75 @@ firebase.firestore.collection = (collectionPath: string): firestore.CollectionRe
19241924
}
19251925
};
19261926

1927-
firebase.firestore.onDocumentSnapshot = (docRef: FIRDocumentReference, optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callback?: (doc: DocumentSnapshot) => void): () => void => {
1927+
firebase.firestore.onDocumentSnapshot = (docRef: FIRDocumentReference, optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callbackOrOnError: (docOrError: DocumentSnapshot | Error) => void, onError: (error: Error) => void): () => void => {
19281928
let includeMetadataChanges = false;
1929+
let onNextCallback: (snapshot: DocumentSnapshot) => void;
1930+
let onErrorCallback: (error: Error) => void;
1931+
19291932
if ((typeof optionsOrCallback) === "function") {
1930-
callback = <(snapshot: DocumentSnapshot) => void>optionsOrCallback;
1931-
} else if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges === true) {
1933+
onNextCallback = <(snapshot: DocumentSnapshot) => void>optionsOrCallback;
1934+
onErrorCallback = callbackOrOnError;
1935+
} else {
1936+
onNextCallback = callbackOrOnError;
1937+
onErrorCallback = onError;
1938+
}
1939+
1940+
if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges === true) {
19321941
includeMetadataChanges = true;
19331942
}
19341943

19351944
const listener = docRef.addSnapshotListenerWithIncludeMetadataChangesListener(includeMetadataChanges, (snapshot: FIRDocumentSnapshot, error: NSError) => {
1936-
if (!error && snapshot) {
1937-
callback(new DocumentSnapshot(snapshot));
1945+
if (error || !snapshot) {
1946+
error && onErrorCallback && onErrorCallback(new Error(error.localizedDescription));
1947+
return;
19381948
}
1949+
onNextCallback && onNextCallback(new DocumentSnapshot(snapshot));
19391950
});
19401951

19411952
// There's a bug resulting this function to be undefined..
19421953
if (listener.remove === undefined) {
19431954
return () => {
19441955
// .. so we're just ignoring anything received from the server (until the callback is set again when 'onSnapshot' is invoked).
1945-
callback = () => {
1956+
onNextCallback = () => {
19461957
};
19471958
};
19481959
} else {
19491960
return () => listener.remove();
19501961
}
19511962
};
19521963

1953-
firebase.firestore.onCollectionSnapshot = (colRef: FIRCollectionReference, optionsOrCallback: any, callback: (snapshot: QuerySnapshot) => void): () => void => {
1964+
firebase.firestore.onCollectionSnapshot = (colRef: FIRCollectionReference, optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callbackOrOnError: (snapshotOrError: QuerySnapshot | Error) => void, onError?: (error: Error) => void): () => void => {
19541965
let includeMetadataChanges = false;
1966+
let onNextCallback: (snapshot: QuerySnapshot) => void;
1967+
let onErrorCallback: (error: Error) => void;
1968+
1969+
// If we passed in an onNext for the first parameter, the next parameter would be onError if provided
1970+
// If options was the first parameter then the next parameter would be onNext if provided
19551971
if ((typeof optionsOrCallback) === "function") {
1956-
callback = <(snapshot: QuerySnapshot) => void>optionsOrCallback;
1957-
} else if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges === true) {
1972+
onNextCallback = <(snapshot: QuerySnapshot) => void>optionsOrCallback;
1973+
onErrorCallback = callbackOrOnError;
1974+
} else {
1975+
onNextCallback = callbackOrOnError; // Can be undefined if callback was not provided
1976+
onErrorCallback = onError; // Can be undefined if onError was not provided
1977+
}
1978+
1979+
if ((<firestore.SnapshotListenOptions>optionsOrCallback).includeMetadataChanges === true) {
19581980
includeMetadataChanges = true;
19591981
}
19601982

19611983
const listener = colRef.addSnapshotListenerWithIncludeMetadataChangesListener(includeMetadataChanges, (snapshot: FIRQuerySnapshot, error: NSError) => {
19621984
if (error || !snapshot) {
1985+
error && onErrorCallback && onErrorCallback(new Error(error.localizedDescription));
19631986
return;
19641987
}
1965-
1966-
callback(new QuerySnapshot(snapshot));
1988+
onNextCallback && onNextCallback(new QuerySnapshot(snapshot));
19671989
});
19681990

19691991
// There's a bug resulting in this function to be undefined..
19701992
if (listener.remove === undefined) {
19711993
return () => {
19721994
// .. so we're just ignoring anything received from the server (until the callback is set again when 'onSnapshot' is invoked).
1973-
callback = () => {
1995+
onNextCallback = () => {
19741996
};
19751997
};
19761998
} else {
@@ -1987,14 +2009,15 @@ firebase.firestore._getCollectionReference = (colRef?: FIRCollectionReference):
19872009

19882010
return {
19892011
id: colRef.collectionID,
1990-
parent: firebase.firestore._getDocumentReference(colRef.parent),
2012+
parent: firebase.firestore.
2013+
mentReference(colRef.parent),
19912014
doc: (documentPath?: string) => firebase.firestore.doc(collectionPath, documentPath),
19922015
add: document => firebase.firestore.add(collectionPath, document),
19932016
get: () => firebase.firestore.get(collectionPath),
19942017
where: (fieldPath: string, opStr: firestore.WhereFilterOp, value: any) => firebase.firestore.where(collectionPath, fieldPath, opStr, value),
19952018
orderBy: (fieldPath: string, directionStr: firestore.OrderByDirection): firestore.Query => firebase.firestore.orderBy(collectionPath, fieldPath, directionStr, colRef),
19962019
limit: (limit: number): firestore.Query => firebase.firestore.limit(collectionPath, limit, colRef),
1997-
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callback?: (snapshot: QuerySnapshot) => void) => firebase.firestore.onCollectionSnapshot(colRef, optionsOrCallback, callback),
2020+
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callbackOrOnError?: (snapshotOrError: QuerySnapshot | Error) => void, onError?: (error: Error) => void) => firebase.firestore.onCollectionSnapshot(colRef, optionsOrCallback, callbackOrOnError, onError),
19982021
startAfter: (document: DocumentSnapshot) => firebase.firestore.startAfter(collectionPath, document, colRef),
19992022
startAt: (document: DocumentSnapshot) => firebase.firestore.startAt(collectionPath, document, colRef),
20002023
endAt: (document: DocumentSnapshot) => firebase.firestore.endAt(collectionPath, document, colRef),
@@ -2019,7 +2042,7 @@ firebase.firestore._getDocumentReference = (docRef?: FIRDocumentReference): fire
20192042
get: () => firebase.firestore.getDocument(collectionPath, docRef.documentID),
20202043
update: (data: any) => firebase.firestore.update(collectionPath, docRef.documentID, data),
20212044
delete: () => firebase.firestore.delete(collectionPath, docRef.documentID),
2022-
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callback?: (snapshot: DocumentSnapshot) => void) => firebase.firestore.onDocumentSnapshot(docRef, optionsOrCallback, callback),
2045+
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: DocumentSnapshot) => void), callbackOrOnError?: (docOrError: DocumentSnapshot | Error) => void, onError?: (error: Error) => void) => firebase.firestore.onDocumentSnapshot(docRef, optionsOrCallback, callbackOrOnError, onError),
20232046
ios: docRef
20242047
};
20252048
};
@@ -2286,7 +2309,7 @@ firebase.firestore._getQuery = (collectionPath: string, query: FIRQuery): firest
22862309
where: (fp: string, os: firestore.WhereFilterOp, v: any): firestore.Query => firebase.firestore.where(collectionPath, fp, os, v, query),
22872310
orderBy: (fp: string, directionStr: firestore.OrderByDirection): firestore.Query => firebase.firestore.orderBy(collectionPath, fp, directionStr, query),
22882311
limit: (limit: number): firestore.Query => firebase.firestore.limit(collectionPath, limit, query),
2289-
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callback?: (snapshot: QuerySnapshot) => void) => firebase.firestore.onCollectionSnapshot(query, optionsOrCallback, callback),
2312+
onSnapshot: (optionsOrCallback: firestore.SnapshotListenOptions | ((snapshot: QuerySnapshot) => void), callbackOrOnError?: (snapshotOrError: QuerySnapshot | Error) => void, onError?: (error: Error) => void) => firebase.firestore.onCollectionSnapshot(query, optionsOrCallback, callbackOrOnError, onError),
22902313
startAfter: (document: DocumentSnapshot) => firebase.firestore.startAfter(collectionPath, document, query),
22912314
startAt: (document: DocumentSnapshot) => firebase.firestore.startAt(collectionPath, document, query),
22922315
endAt: (document: DocumentSnapshot) => firebase.firestore.endAt(collectionPath, document, query),

0 commit comments

Comments
 (0)