Skip to content

Review pass & fixup of the control directive & related code #63068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: prototype/signal-forms
Choose a base branch
from

Conversation

mmalerba
Copy link
Contributor

@mmalerba mmalerba commented Aug 9, 2025

No description provided.

@mmalerba mmalerba requested review from leonsenft and kirjs August 9, 2025 09:18
@mmalerba mmalerba added area: forms target: feature This PR is targeted for a feature branch (outside of main and semver branches) labels Aug 9, 2025
@ngbot ngbot bot added this to the Backlog milestone Aug 9, 2025
@angular-robot angular-robot bot added detected: feature PR contains a feature commit area: docs Related to the documentation labels Aug 9, 2025
Copy link
Contributor Author

@mmalerba mmalerba left a comment

Choose a reason for hiding this comment

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

Calling out some TODOs in case we want to address any of them during this PR

readonly errors?: InputSignal<readonly ValidationError[] | undefined>;
// TODO: should we have an input for binding disabled reason?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO callout: Should we have an input for binding disabled reason?

* will automatically bind the hidden status from the bound field to this input.
*/
readonly hidden?: InputSignal<boolean | undefined>;
// TODO: what do we do about the whole valid != invalid thing?
Copy link
Contributor Author

@mmalerba mmalerba Aug 9, 2025

Choose a reason for hiding this comment

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

TODO callout: what do we do about the whole valid != !invalid thing?

  • Should we bind both of them? neither? treat valid+pending as valid? some kind of combined tri-/quad-state?
  • Should we allow binding in the pending state?

Copy link
Contributor Author

@mmalerba mmalerba Aug 11, 2025

Choose a reason for hiding this comment

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

I think we should do:

  • valid: false if there are any errors, true otherwise
  • pending: true if there are any pending validators, false otherwise.

Notably this definition of valid is different than what FieldState.valid is, but I think it makes sense to convert it at this point to a value that makes more sense for the UI (which basically just want to know "do I show scary red or not?")

* will automatically bind the value patterns from the bound field to this input.
*/
readonly pattern?: InputSignal<readonly RegExp[] | undefined>;
// TODO: what should we name this output? `touch` feels weird. The rest of the inputs here are
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO callout: what should we name this output? touch feels weird. The rest of the inputs here are named after their corresponding DOM concept (when applicable). Following that pattern, blur might make sense, though maybe we consider this a separate thing that only happens to align with blur by default. Some alternative options:

  • blur
  • touchEvent
  • touched (overlaps with the input name, could make it a InputSignal | ModelSignal | OutputRef)
  • just remove this and don't allow customization of this behavior

// TODO: Do we actually need to require the lack of a `checked` input?
// The implementation currently doesn't enforce this. It *does* enforce the lack of a `value`
// input for the `FormCheckboxControl` which should be sufficient to tell them apart.
// TODO: We currently require that a `checked` input not be present, as we may want to introduce a
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO callout: We currently require that a checked input not be present, as we may want to introduce a third kind of form control for radio buttons that defines both a value and checked input. We are still evaluating whether this makes sense, but if we decide not to persue this we can remove this restriction.

cc @alxhub on this one, since he did some experimentation with it

readonly checked: ModelSignal<boolean>;
// TODO: maybe this doesn't have to be strictly `undefined`? It just can't be a model signal.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO callout: maybe this doesn't have to be strictly undefined? It just can't be a model signal. Typescript doesn't really have a way to do any-but, but we could maybe introduce an optional generic for it?

@@ -160,9 +193,11 @@ export class Control<T> {
input.addEventListener('blur', () => this.state().markAsTouched());

this.maybeSynchronize(() => this.state().readonly(), withBooleanAttribute(input, 'readonly'));
// TODO: consider making a global configuration option for using aria-disabled instead.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO callout: consider making a global configuration option for using aria-disabled instead.

type NgControl,
type ValidationErrors,
type ValidatorFn,
} from '@angular/forms';
import {REQUIRED} from '../api/property';
import type {FieldState} from '../api/types';

// TODO: Also consider supporting (if possible):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO callout: Also consider supporting (if possible):

  • hasError
  • getError
  • reset
  • name
  • path
  • markAs[Touched,Dirty,etc.]
  • updateValueAndValidity

@mmalerba mmalerba requested review from alxhub and removed request for JeanMeche and AndrewKushnir August 9, 2025 09:25
@pullapprove pullapprove bot requested a review from JeanMeche August 9, 2025 09:25
@mmalerba mmalerba changed the title feat(forms): add missing builtin property hooks for custom controls Review pass & fixup of the control directive & related code Aug 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: docs Related to the documentation area: forms detected: feature PR contains a feature commit target: feature This PR is targeted for a feature branch (outside of main and semver branches)
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

1 participant