Skip to content

fix(angular): align formField control binding with Angular#230

Merged
Brooooooklyn merged 1 commit intomainfrom
fix-formfield-control-regression
Apr 15, 2026
Merged

fix(angular): align formField control binding with Angular#230
Brooooooklyn merged 1 commit intomainfrom
fix-formfield-control-regression

Conversation

@Brooooooklyn
Copy link
Copy Markdown
Member

@Brooooooklyn Brooooooklyn commented Apr 15, 2026

Angular's control-directives pipeline treats [formField] as a normal property binding and then inserts separate controlCreate/control instructions. Our Rust pipeline had drifted from that logic and rewrote [formField] into a custom ControlOp carrying the bound value, which emitted legacy output like ɵɵcontrol(ctx.myField, "formField") without ever writing the directive input via ɵɵproperty("formField", ...). In Angular 21 signal forms this leaves FormField.field unset and can surface as NG0950 at runtime.

This change restores the expected control flow for template bindings:

  • keep [formField] as a regular PropertyOp
  • emit a separate ControlOp after the property update
  • reify ControlOp to zero-arg ɵɵcontrol()
  • stop extracting duplicate const metadata from ControlOp itself

The tests now cover both the regression and Angular's mixed-order control fixture behavior:

  • [formField] must emit ɵɵproperty("formField", ...) plus ɵɵcontrol()
  • legacy ɵɵcontrol(value, "formField") output is rejected
  • mixed [formField]/[value] bindings preserve update order
  • extracted const metadata preserves per-element binding order

Verified with targeted cargo test runs for the new regression, control binding extraction, mixed property ordering, const ordering, pipe slot propagation, and the existing [field] non-control regression.


Note

Medium Risk
Changes how [formField] bindings are specialized, reified, and counted, which can affect generated template update code and directive matching/consts ordering. Scope is limited to control binding pipeline and covered by new integration tests, but regressions would surface at runtime in form control sync.

Overview
Aligns [formField] handling with Angular by emitting it as a normal PropertyOp update plus a following ControlOp, instead of rewriting it into a value-carrying control binding.

Updates reification so ControlOp generates a zero-arg ɵɵcontrol() call, stops extracting directive-matching const metadata from ControlOp, and fixes var slot counting so ControlOp contributes 0 vars (the value is accounted for by the preceding property update).

Adds regression tests asserting ɵɵproperty("formField", ...) + ɵɵcontrol() output, preserving mixed binding order and consts ordering, and ensuring vars counts don’t inflate.

Reviewed by Cursor Bugbot for commit 8d189cf. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f8eae6f96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Angular's control-directives pipeline treats [formField] as a normal property binding and then inserts separate controlCreate/control instructions. Our Rust pipeline had drifted from that logic and rewrote [formField] into a custom ControlOp carrying the bound value, which emitted legacy output like ɵɵcontrol(ctx.myField, "formField") without ever writing the directive input via ɵɵproperty("formField", ...). In Angular 21 signal forms this leaves FormField.field unset and can surface as NG0950 at runtime.

This change restores the expected control flow for template bindings:
- keep [formField] as a regular PropertyOp
- emit a separate ControlOp after the property update
- reify ControlOp to zero-arg ɵɵcontrol()
- stop extracting duplicate const metadata from ControlOp itself

The tests now cover both the regression and Angular's mixed-order control fixture behavior:
- [formField] must emit ɵɵproperty("formField", ...) plus ɵɵcontrol()
- legacy ɵɵcontrol(value, "formField") output is rejected
- mixed [formField]/[value] bindings preserve update order
- extracted const metadata preserves per-element binding order

Verified with targeted cargo test runs for the new regression, control binding extraction, mixed property ordering, const ordering, pipe slot propagation, and the existing [field] non-control regression.
@Brooooooklyn Brooooooklyn force-pushed the fix-formfield-control-regression branch from 7f8eae6 to 8d189cf Compare April 15, 2026 09:30
@Brooooooklyn Brooooooklyn merged commit a185dcc into main Apr 15, 2026
9 checks passed
@Brooooooklyn Brooooooklyn deleted the fix-formfield-control-regression branch April 15, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

formField directive broken when using oxc-angular plugin

1 participant