Skip to content

Commit d40aba1

Browse files
docs(zones): show how to keep AngularFire calls in an injection context
The zone-wrappers guide explains what the "outside of an Injection context" warning means and how to change its log level, but never shows how to fix the code that triggers it. #3629 asks for exactly that. This adds a "Keeping calls inside an injection context" section covering the most common trigger: an AngularFire API called inside an async callback (for example a Firestore query built inside a switchMap on the signed-in user), where the callback runs after the synchronous injection context is gone. The recipe captures an EnvironmentInjector while the context is active and re-establishes it inside the callback with runInInjectionContext, plus a note to prefer hoisting the call out of the callback when it doesn't depend on the async value. Docs-only; no code or behavior change. Fixes #3629
1 parent 8dfcc2c commit d40aba1

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

docs/zones.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,37 @@ When an application is unstable change-detection, two-way binding, and rehydrati
1818

1919
There are a number of situations where AngularFire's Zone wrapping is inconsequential such adding/deleting/updating a document in response to user-input, signing a user in, calling a Cloud Function, etc. So long as no long-lived side-effects are kicked off, your application should be ok. Most Promise based APIs are fairly safe without zone wrapping.
2020

21+
## Keeping calls inside an injection context
22+
23+
A common way to trip the warning is calling an AngularFire API from inside an asynchronous callback, for example building a Firestore query inside a `switchMap` on the signed-in user. The surrounding service is created inside an injection context, but the callback runs *later*, after that context is gone, so AngularFire can no longer wrap the call.
24+
25+
Capture an `EnvironmentInjector` while the context is still active (any field initializer or constructor), then re-establish it inside the callback with [`runInInjectionContext`](https://angular.dev/api/core/runInInjectionContext):
26+
27+
```ts
28+
private readonly injector = inject(EnvironmentInjector);
29+
30+
readonly todos$ = this.user$.pipe(
31+
switchMap((user) =>
32+
runInInjectionContext(this.injector, () =>
33+
collectionData(collection(this.firestore, `users/${user.uid}/todos`)),
34+
),
35+
),
36+
);
37+
```
38+
39+
Inside `runInInjectionContext`, AngularFire can wrap the call again, so the SSR/change-detection guarantees are restored and the warning goes away.
40+
41+
If a call doesn't depend on the async value, prefer hoisting it out of the callback entirely and running it once where the injection context is still active:
42+
43+
```ts
44+
// Built once where the context is live, then reused, so no wrapping is needed:
45+
private readonly items$ = collectionData(collection(this.firestore, "items"));
46+
47+
readonly refreshed$ = this.refresh$.pipe(switchMap(() => this.items$));
48+
```
49+
50+
Reach for `runInInjectionContext` only when the call genuinely must run inside the callback, as the per-user query above does (it needs the signed-in user's `uid`).
51+
2152
## Logging
2253

2354
You may see a log warning, `Calling Firebase APIs outside of an Injection context may destabilize your application leading to subtle change-detection and hydration bugs. Find more at https://github.com/angular/angularfire/blob/main/docs/zones.md` when developing your application.

0 commit comments

Comments
 (0)