Skip to content

refactor(select): migrate select to signal forms#2310

Draft
spike-rabbit wants to merge 1 commit into
mainfrom
refactor/select/signal-form-control-value
Draft

refactor(select): migrate select to signal forms#2310
spike-rabbit wants to merge 1 commit into
mainfrom
refactor/select/signal-form-control-value

Conversation

@spike-rabbit

@spike-rabbit spike-rabbit commented Jul 9, 2026

Copy link
Copy Markdown
Member

Summary\nUse signal form controls for select and align the value model with the new API.\n\n## Breaking changes\n- Drop NG_VALUE_ACCESSOR from select.\n- Single-value select now includes undefined.\n- Multi-value select no longer accepts undefined.\n\n## Notes\n- The select-specific signal form migration required small follow-up adjustments in nearby consumers and examples.\n- The test suite was updated to reflect the new select behavior.\n\n

Checklist\n- [x] Relevant tests updated\n- [x] Breaking changes documented

Use signal form controls for select and align the value model with the new API.

BREAKING CHANGE: drop NG_VALUE_ACCESSOR from select.

Changed select to use Angular signal form models instead of ControlValueAccessor. Update consumers to bind through signal form APIs.

BREAKING CHANGE: single-value select now includes undefined.

Changed the single-value select model to represent an unselected state explicitly. Update code that assumed the value was always defined.

BREAKING CHANGE: multi-value select no longer accepts undefined.

Changed the multi-value select model to always use an array. Initialize callers with [] instead of undefined and remove undefined handling from related code.

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

Copy link
Copy Markdown
Contributor

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 refactors the select component's selection strategies to use Angular's new signal-based form controls (FormValueControl and ModelSignal) instead of the traditional ControlValueAccessor. It also updates related components, tests, and examples to support nullable types and the new signal APIs. The review feedback highlights a style guide violation where effect() is used to propagate state changes in SiSelectSelectionStrategy, which should be refactored to use computed(). Additionally, a misleading JSDoc comment regarding the default value in SiSelectSingleValueDirective needs to be corrected.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +64 to 70
constructor() {
effect(() => {
const arrayValue = this.toArrayValue(this.value());
// That way the effect only tracks value(), and the reads/writes of selectedRows/rows inside onValueChange no longer feed back into it.
untracked(() => this.selectOptions.onValueChange(arrayValue));
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

According to the Repository Style Guide (line 38), effect() must not be used for propagation of state changes, as this can lead to ExpressionChangedAfterItHasBeenChecked errors, infinite circular updates, or unnecessary change detection cycles.

Instead of pushing updates from the selection strategy to the options strategy using an effect, the options strategy (SiSelectOptionsStrategy) should reactively compute its selected state by reading the selection strategy's value signal directly (e.g., using computed()).

References
  1. Do NOT use effect() for propagation of state changes — this leads to ExpressionChangedAfterItHasBeenChecked errors, infinite circular updates, or unnecessary change detection cycles. Use computed() instead to model state that depends on other state (link)

*/
override allowMultiple = false;

/** @defaultValue [] */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The JSDoc comment @defaultValue [] is misleading because the default value of model<T>() is undefined (not an empty array []). Please update the documentation to reflect the correct default value.

Suggested change
/** @defaultValue [] */
/** @defaultValue undefined */

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.

1 participant