Skip to content

Commit cd094cd

Browse files
ShaneKthetaPC
andauthored
docs(angular): correct OnPush guidance in lifecycle note (#4694)
* docs(angular): document app shell change detection requirement on Angular 22 * docs(angular): correct OnPush guidance in lifecycle note * chore(git): reverting change * docs(lifecycle): phrasing Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com> --------- Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
1 parent 07f9946 commit cd094cd

2 files changed

Lines changed: 25 additions & 2 deletions

File tree

docs/angular/lifecycle.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ For more info on the Angular Component Life Cycle events, visit their [component
2828

2929
:::note
3030

31-
Components that use `ion-nav` or `ion-router-outlet` should not use the `OnPush` change detection strategy. Doing so will prevent lifecycle hooks such as `ngOnInit` from firing. Additionally, asynchronous state changes may not render properly.
31+
If your pages keep state in plain fields rather than signals, the component hosting `ion-router-outlet` or `ion-tabs` needs eager change detection, as does every component between it and your application root. A change detection pass starts at the application root and skips a clean `OnPush` view along with everything below it, so an `OnPush` component above the outlet stops updates from reaching the routed pages under it. The pages themselves can use `OnPush`, as long as their state is a signal or they call `markForCheck()`.
32+
33+
On **Angular 18 through 21** this only affects you if you set `OnPush` on those components yourself, because a component that does not declare a strategy is eager.
34+
35+
**Angular 22** makes `OnPush` the default for components that do not declare one, so refer to [Change detection on Angular 22](/docs/angular/zoneless.mdx#change-detection-on-angular-22) for what your app shell has to declare.
3236

3337
:::
3438

docs/angular/zoneless.mdx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ You do not need to change these. Angular schedules change detection for them in
2828

2929
:::note[Angular 22]
3030

31-
Angular 22 also makes `OnPush` the default change detection strategy. Under `OnPush`, synchronous state set as a plain field (including in the lifecycle hooks above) no longer re-renders on its own, even though Ionic notifies Angular. Signals still update the view. For the migration path, refer to the [OnPush Change Detection section of the Ionic 9 upgrade guide](/docs/updating/9-0.mdx#onpush-change-detection-on-angular-22).
31+
Angular 22 also makes `OnPush` the default change detection strategy. Under `OnPush`, synchronous state set as a plain field (including in the lifecycle hooks above) no longer re-renders on its own, even though Ionic notifies Angular. Signals still update the view. Refer to [Change detection on Angular 22](#change-detection-on-angular-22) for what this means for your app shell, and to the [OnPush Change Detection section of the Ionic 9 upgrade guide](/docs/updating/9-0.mdx#onpush-change-detection-on-angular-22) for the migration steps.
3232

3333
:::
3434

@@ -153,6 +153,25 @@ export class AppComponent {
153153
}
154154
```
155155

156+
## Change detection on Angular 22
157+
158+
On Angular 22 a component that does not declare a strategy is `OnPush`. If your pages keep state in plain fields rather than signals, every component from your application root down to the one hosting `ion-router-outlet` or `ion-tabs` (your app shell) must stay eager. A tick starts at the application root and skips a clean `OnPush` view and everything below it, so an `OnPush` ancestor strands the page even when the page itself is eager:
159+
160+
```ts
161+
import { ChangeDetectionStrategy, Component } from '@angular/core';
162+
163+
@Component({
164+
selector: 'app-root',
165+
changeDetection: ChangeDetectionStrategy.Eager,
166+
template: '<ion-router-outlet></ion-router-outlet>',
167+
})
168+
export class AppComponent {}
169+
```
170+
171+
If other components sit between your application root and `ion-router-outlet`, each of them needs the same declaration. Pages that set state through signals, or that call `markForCheck()`, are unaffected: both mark the ancestor chain, so a tick reaches them whatever the shell declares. Converting your pages that way is the alternative to keeping the shell eager.
172+
173+
Hosting an `ion-nav` is fine either way, because its pages are attached as root views and are checked independently of the component hosting them.
174+
156175
## Staying on Zone.js
157176

158177
If you are not ready to adopt zoneless change detection, you can opt back into Zone.js with `provideZoneChangeDetection()`. Refer to the [Keeping Zone.js section of the Ionic 9 upgrade guide](/docs/updating/9-0.mdx#keeping-zonejs) for the exact configuration.

0 commit comments

Comments
 (0)