diff --git a/src/app/field-info.ts b/src/app/field-info.ts new file mode 100644 index 0000000..61453d9 --- /dev/null +++ b/src/app/field-info.ts @@ -0,0 +1,37 @@ +import { Directive, effect, inject, input, TemplateRef, ViewContainerRef } from '@angular/core'; +import { FieldTree } from '@angular/forms/signals'; +import { FIELD_INFO } from './form-props'; + +@Directive({ + selector: '[fieldInfo]', + standalone: true, +}) +export class FieldInfo { + readonly fieldInfo = input.required>(); + readonly #templateRef = inject(TemplateRef<{ $implicit: string; cssClass: string }>); + readonly #viewContainer = inject(ViewContainerRef); + + constructor() { + effect(() => { + const field = this.fieldInfo()(); + this.#viewContainer.clear(); + + let messages: { info: string; cssClass: 'info' | 'invalid' }[] = []; + + if (field.pending()) { + messages = [{ info: 'Checking availability ...', cssClass: 'info' }]; + } else if (field.touched() && field.errors().length > 0) { + messages = field.errors().map((e) => ({ info: e.message || 'Invalid', cssClass: 'info' })); + } else if (field.hasMetadata(FIELD_INFO)) { + messages = [{ info: field.metadata(FIELD_INFO)!, cssClass: 'info' }]; + } + + messages.forEach((message) => { + this.#viewContainer.createEmbeddedView(this.#templateRef, { + $implicit: message.info, + cssClass: message.cssClass, + }); + }); + }); + } +} diff --git a/src/app/form-props.ts b/src/app/form-props.ts new file mode 100644 index 0000000..cbfa5f0 --- /dev/null +++ b/src/app/form-props.ts @@ -0,0 +1,3 @@ +import { createMetadataKey } from "@angular/forms/signals"; + +export const FIELD_INFO = createMetadataKey() diff --git a/src/app/registration-form-3/registration-form-3.html b/src/app/registration-form-3/registration-form-3.html index 399c5a6..08004df 100644 --- a/src/app/registration-form-3/registration-form-3.html +++ b/src/app/registration-form-3/registration-form-3.html @@ -14,10 +14,7 @@

Version 3: Child Forms and Custom UI Controls

[field]="registrationForm.username" [ariaInvalid]="ariaInvalidState(registrationForm.username)" /> - @if (registrationForm.username().pending()) { - Checking availability ... - } - + {{ message }} @@ -32,7 +29,7 @@

Version 3: Child Forms and Custom UI Controls

[field]="registrationForm.age" [ariaInvalid]="ariaInvalidState(registrationForm.age)" /> - + {{ message }} @@ -45,7 +42,7 @@

Version 3: Child Forms and Custom UI Controls

[field]="registrationForm.password.pw1" [ariaInvalid]="ariaInvalidState(registrationForm.password.pw1)" /> - + {{ message }} - + {{ message }}
@@ -76,11 +73,11 @@

Version 3: Child Forms and Custom UI Controls

/> - + {{ message }} } - + {{ message }}