mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
feat(forms): expose element on signal forms Field directive
This allows for easier focusing of the relevant element based on the
`field` property of a `ValidationError`
(cherry picked from commit aff8b248b3)
This commit is contained in:
parent
91532626a9
commit
f254ff4f2e
3 changed files with 20 additions and 14 deletions
|
|
@ -20,7 +20,6 @@ import { ɵCONTROL } from '@angular/core';
|
|||
import { ɵControl } from '@angular/core';
|
||||
import { ɵcontrolUpdate } from '@angular/core';
|
||||
import { ɵFieldState } from '@angular/core';
|
||||
import { ɵInteropControl } from '@angular/core';
|
||||
import { ɵɵcontrolCreate } from '@angular/core';
|
||||
|
||||
// @public
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import { ɵCONTROL } from '@angular/core';
|
|||
import { ɵControl } from '@angular/core';
|
||||
import { ɵcontrolUpdate } from '@angular/core';
|
||||
import { ɵFieldState } from '@angular/core';
|
||||
import { ɵInteropControl } from '@angular/core';
|
||||
import { ɵɵcontrolCreate } from '@angular/core';
|
||||
|
||||
// @public
|
||||
|
|
@ -147,19 +146,18 @@ export class Field<T> implements ɵControl<T> {
|
|||
readonly update: typeof ɵcontrolUpdate;
|
||||
};
|
||||
// (undocumented)
|
||||
readonly classes: (readonly [string, i0.Signal<boolean>])[];
|
||||
readonly element: HTMLElement;
|
||||
// (undocumented)
|
||||
readonly field: i0.InputSignal<FieldTree<T>>;
|
||||
protected getOrCreateNgControl(): InteropNgControl;
|
||||
// (undocumented)
|
||||
readonly injector: Injector;
|
||||
// (undocumented)
|
||||
readonly state: i0.Signal<[T] extends [_angular_forms.AbstractControl<any, any, any>] ? CompatFieldState<T, string | number> : FieldState<T, string | number>>;
|
||||
// (undocumented)
|
||||
static ɵdir: i0.ɵɵDirectiveDeclaration<Field<any>, "[field]", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
||||
// (undocumented)
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<Field<any>, never>;
|
||||
get ɵinteropControl(): ɵInteropControl | undefined;
|
||||
// (undocumented)
|
||||
ɵregister(): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
|||
|
|
@ -8,17 +8,18 @@
|
|||
|
||||
import {
|
||||
computed,
|
||||
ɵɵcontrolCreate as createControlBinding,
|
||||
Directive,
|
||||
effect,
|
||||
ElementRef,
|
||||
inject,
|
||||
InjectionToken,
|
||||
Injector,
|
||||
input,
|
||||
ɵcontrolUpdate as updateControlBinding,
|
||||
ɵCONTROL,
|
||||
ɵControl,
|
||||
ɵcontrolUpdate as updateControlBinding,
|
||||
ɵInteropControl,
|
||||
ɵɵcontrolCreate as createControlBinding,
|
||||
} from '@angular/core';
|
||||
import {NG_VALUE_ACCESSOR, NgControl} from '@angular/forms';
|
||||
import {InteropNgControl} from '../controls/interop_ng_control';
|
||||
|
|
@ -71,14 +72,18 @@ const controlInstructions = {
|
|||
],
|
||||
})
|
||||
export class Field<T> implements ɵControl<T> {
|
||||
private readonly injector = inject(Injector);
|
||||
readonly element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;
|
||||
readonly injector = inject(Injector);
|
||||
readonly field = input.required<FieldTree<T>>();
|
||||
readonly state = computed(() => this.field()());
|
||||
|
||||
readonly [ɵCONTROL] = controlInstructions;
|
||||
|
||||
private config = inject(SIGNAL_FORMS_CONFIG, {optional: true});
|
||||
/** @internal */
|
||||
readonly classes = Object.entries(this.config?.classes ?? {}).map(
|
||||
([className, computation]) => [className, computed(() => computation(this.state()))] as const,
|
||||
);
|
||||
readonly field = input.required<FieldTree<T>>();
|
||||
readonly state = computed(() => this.field()());
|
||||
readonly [ɵCONTROL] = controlInstructions;
|
||||
|
||||
/** Any `ControlValueAccessor` instances provided on the host element. */
|
||||
private readonly controlValueAccessors = inject(NG_VALUE_ACCESSOR, {optional: true, self: true});
|
||||
|
|
@ -86,7 +91,11 @@ export class Field<T> implements ɵControl<T> {
|
|||
/** A lazily instantiated fake `NgControl`. */
|
||||
private interopNgControl: InteropNgControl | undefined;
|
||||
|
||||
/** A `ControlValueAccessor`, if configured, for the host component. */
|
||||
/**
|
||||
* A `ControlValueAccessor`, if configured, for the host component.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
get ɵinteropControl(): ɵInteropControl | undefined {
|
||||
return this.controlValueAccessors?.[0] ?? this.interopNgControl?.valueAccessor ?? undefined;
|
||||
}
|
||||
|
|
@ -96,7 +105,7 @@ export class Field<T> implements ɵControl<T> {
|
|||
return (this.interopNgControl ??= new InteropNgControl(this.state));
|
||||
}
|
||||
|
||||
// TODO: https://github.com/orgs/angular/projects/60/views/1?pane=issue&itemId=131861631
|
||||
/** @internal */
|
||||
ɵregister() {
|
||||
// Register this control on the field it is currently bound to. We do this at the end of
|
||||
// initialization so that it only runs if we are actually syncing with this control
|
||||
|
|
|
|||
Loading…
Reference in a new issue