Skip to content

Switch v0.8 Angular Renderer to use OnPush change detection#877

Closed
gspencergoog wants to merge 5 commits intogoogle:mainfrom
gspencergoog:angular_on_push
Closed

Switch v0.8 Angular Renderer to use OnPush change detection#877
gspencergoog wants to merge 5 commits intogoogle:mainfrom
gspencergoog:angular_on_push

Conversation

@gspencergoog
Copy link
Collaborator

Description

This PR refactors all components in the v0.8 Angular renderer from ChangeDetectionStrategy.Eager to ChangeDetectionStrategy.OnPush for improved rendering performance and determinism.

Changes

  • renderers/angular/v0_8/components/: Updated components to explicitly consume @Input variables and bind with OnPush change detection.
  • renderers/angular/v0_8/rendering/renderer.ts: Replaced signal effect setups with @Input() variables and ngOnChanges support to satisfy standard reactive input triggering.
  • renderers/angular/v0_8/rendering/renderer.spec.ts: Updated fixture tick(10) triggers inside async assertions because OnPush requires explicit detection cycles in tests.

Impact & Risks

  • No Breaking Changes: Keeps public APIs stable.
  • Performance Benefits: Avoids unnecessary full component node updates on large tree mutations.

Testing

  1. Run and verify that renderers/angular/v0_8 unit tests successfully pass with continuous integration builds.

@github-project-automation github-project-automation bot moved this to Todo in A2UI Mar 17, 2026
@gspencergoog gspencergoog changed the title Angular on push Switch Angular Renderer to use OnPush change detection Mar 17, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a significant and valuable refactoring, migrating the v0.8 Angular renderer components to use ChangeDetectionStrategy.OnPush. This is an excellent move for performance and determinism. The changes are well-executed, and the addition of comprehensive unit tests for the components is a great enhancement. My review focuses on a few areas to further improve code quality: I've identified a potential bug in a catalog binding, and have suggestions to improve type safety and the robustness of some of the new tests.

Comment on lines 128 to +130
inputBinding('text', () => properties.text ?? null),
inputBinding('label', () => properties.label),
inputBinding('textFieldType', () => properties.textFieldType),
inputBinding('inputType', () => properties.textFieldType),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There appears to be a mismatch in the TextField catalog binding. The binding is configured for an input named inputType, but the TextField component's input property is named textFieldType. This will prevent the textFieldType property from being correctly passed to the component, likely causing it to default to 'text' regardless of the model's value.

Suggested change
inputBinding('text', () => properties.text ?? null),
inputBinding('label', () => properties.label),
inputBinding('textFieldType', () => properties.textFieldType),
inputBinding('inputType', () => properties.textFieldType),
inputBinding('text', () => properties.text ?? null),
inputBinding('label', () => properties.label),
inputBinding('textFieldType', () => properties.textFieldType),

Comment on lines +291 to +295
fixture.detectChanges();
await fixture.whenStable();
fixture.detectChanges();
await fixture.whenStable();
fixture.detectChanges();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This sequence of detectChanges and whenStable calls, while likely correct for handling nested async rendering, is a bit difficult to read and could be brittle. To improve test clarity and maintainability, I recommend extracting this stabilization logic into a shared helper function. This would make the test's intent clearer and allow for easier reuse across other tests that might face similar async scenarios.


if (this.areHintedStyles(styles)) {
additionalStyles = styles[usageHint ?? 'body'];
additionalStyles = (styles as any)[usageHint ?? 'body'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of as any here weakens type safety. The areHintedStyles type guard is intended to prevent this, but there's a small inconsistency: it checks for an h6 key, which is missing from the HintedStyles interface definition.

To improve this, I recommend two changes:

  1. Add h6: Record<string, string>; to the HintedStyles interface to align it with the type guard.
  2. Replace the as any cast with a more type-safe approach, like (styles as HintedStyles)[(usageHint ?? 'body') as keyof HintedStyles];.

fixture.detectChanges();

// Wait for async render
await new Promise((resolve) => setTimeout(resolve, 10));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using setTimeout in unit tests can introduce flakiness and make them less deterministic. Angular's testing utilities provide more robust ways to handle asynchronous operations. I recommend replacing await new Promise((resolve) => setTimeout(resolve, 10)); with await fixture.whenStable(); to wait for promises like the dynamic component import to resolve.

Copy link
Collaborator

@jacobsimionato jacobsimionato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw @ditman did something similar and abandoned it in #805 , and @crisbeto added EAGER explicitly in #726 to prevent a breakage - not sure if it was a theoretical breakage or a real breakage. Maybe we should consult with one of them before submitting, in case there are unintended consequences in google's monorepo? Does this block submitting v0.9 code, or it's a nice to have for consistency?

@gspencergoog
Copy link
Collaborator Author

I saw @ditman did something similar and abandoned it in #805 , and @crisbeto added EAGER explicitly in #726 to prevent a breakage - not sure if it was a theoretical breakage or a real breakage. Maybe we should consult with one of them before submitting, in case there are unintended consequences in google's monorepo? Does this block submitting v0.9 code, or it's a nice to have for consistency?

It is orthogonal to 0.9, although 0.9 is set up to use OnPush. It doesn't block anything. I agree we should get more eyes on (once I fix the build issues).

@ditman
Copy link
Collaborator

ditman commented Mar 17, 2026

We abandoned my prior attempt because the testing story is not good, and we're not sure of what can break by blanket-applying this to the v0.8 codebase. The deal was to apply these as bugs were found on a per-component basis.

I think it's okay to do v0.9 fully based on OnPush, but leave 0.8 as is, and bring in fixes as we find them via bug reports (I suppose those are going to be mostly internal bugs, if any)

(/cc @jgindin)

@gspencergoog gspencergoog changed the title Switch Angular Renderer to use OnPush change detection Switch v0.8 Angular Renderer to use OnPush change detection Mar 17, 2026
@gspencergoog
Copy link
Collaborator Author

We abandoned my prior attempt because the testing story is not good, and we're not sure of what can break by blanket-applying this to the v0.8 codebase. The deal was to apply these as bugs were found on a per-component basis.

I think it's okay to do v0.9 fully based on OnPush, but leave 0.8 as is, and bring in fixes as we find them via bug reports (I suppose those are going to be mostly internal bugs, if any)

(/cc @jgindin)

Okay, I'll close this for now, then, and abandon the change until we see reasons to change it.

@github-project-automation github-project-automation bot moved this from Todo to Done in A2UI Mar 17, 2026
@gspencergoog
Copy link
Collaborator Author

Oh, wait, there are a lot of new tests here. I think I'll just revert the OnPush changes, but keep the tests.

@gspencergoog gspencergoog reopened this Mar 17, 2026
@gspencergoog
Copy link
Collaborator Author

Closing in favor of #882

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants