Repository: angular/angular
File: packages/forms/signals/src/directive/form_field_directive.ts (TypeScript)

Code before:
 * This directive has several responsibilities:
 * 1. Two-way binds the field state's value with the UI control's value
 * 2. Binds additional forms related state on the field state to the UI control (disabled, required, etc.)
 * 3. Relays relevant events on the control to the field state (e.g. marks touched on blur)
 * 4. Provides a fake `NgControl` that implements a subset of the features available on the
 *    reactive forms `NgControl`. This is provided to improve interoperability with controls
 *    designed to work with reactive forms. It should not be used by controls written for signal
 *    forms.
 *
 * @category control
 * @experimental 21.0.0
 */
@Directive({
  selector: '[formField]',
  exportAs: 'formField',
  providers: [
    {provide: FORM_FIELD, useExisting: FormField},
    {provide: NgControl, useFactory: () => inject(FormField).interopNgControl},
    {
      provide: FORM_FIELD_PARSE_ERRORS,
      useFactory: () => inject(FormField).parseErrorsSource,
    },
  ],
})
export class FormField<T> {
  readonly formField = input.required<Field<T>>();

  /** @internal */
  readonly renderer = inject(Renderer2);

  /** @internal */
  readonly destroyRef = inject(DestroyRef);

  /**
   * `FieldState` for the currently bound field.
   */
  readonly state = computed(() => this.formField()());

  /**
   * The node injector for the element this field binding.
   */
  readonly injector = inject(Injector);

  /**
   * The DOM element hosting this field binding.
   */
  readonly element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;

  // Compute some helper booleans about the type of element we're sitting on.
  private readonly elementIsNativeFormElement = isNativeFormElement(this.element);
  private readonly elementAcceptsNumericValues = isNumericFormElement(this.element);

Review comment (suggestion):
can we change this to `readonly field = input.required<Field<T>>({alias: 'formField'});` that way the property name will make more sense

Code after:
 * This directive has several responsibilities:
 * 1. Two-way binds the field state's value with the UI control's value
 * 2. Binds additional forms related state on the field state to the UI control (disabled, required, etc.)
 * 3. Relays relevant events on the control to the field state (e.g. marks touched on blur)
 * 4. Provides a fake `NgControl` that implements a subset of the features available on the
 *    reactive forms `NgControl`. This is provided to improve interoperability with controls
 *    designed to work with reactive forms. It should not be used by controls written for signal
 *    forms.
 *
 * @category control
 * @experimental 21.0.0
 */
@Directive({
  selector: '[formField]',
  exportAs: 'formField',
  providers: [
    {provide: FORM_FIELD, useExisting: FormField},
    {provide: NgControl, useFactory: () => inject(FormField).interopNgControl},
    {
      provide: FORM_FIELD_PARSE_ERRORS,
      useFactory: () => inject(FormField).parseErrorsSource,
    },
  ],
})
export class FormField<T> {
  readonly field = input.required<Field<T>>({alias: 'formField'});

  /** @internal */
  readonly renderer = inject(Renderer2);

  /** @internal */
  readonly destroyRef = inject(DestroyRef);

  /**
   * `FieldState` for the currently bound field.
   */
  readonly state = computed(() => this.field()());

  /**
   * The node injector for the element this field binding.
   */
  readonly injector = inject(Injector);

  /**
   * The DOM element hosting this field binding.
   */
  readonly element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;

  // Compute some helper booleans about the type of element we're sitting on.
  private readonly elementIsNativeFormElement = isNativeFormElement(this.element);
  private readonly elementAcceptsNumericValues = isNumericFormElement(this.element);