From 15806d7c9fd696e4f70f9795dee2a592bd7cb834 Mon Sep 17 00:00:00 2001 From: Benn Snyder Date: Tue, 27 Jan 2026 08:47:31 -0500 Subject: [PATCH] HXIDP-5181 Allow form text fields to render custom field status content (#11523) --- .../components/widgets/text/text.widget.html | 13 +++++--- .../widgets/text/text.widget.spec.ts | 31 +++++++++++++++++++ .../components/widgets/text/text.widget.ts | 25 +++++++++++++-- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/lib/core/src/lib/form/components/widgets/text/text.widget.html b/lib/core/src/lib/form/components/widgets/text/text.widget.html index 4ff765d9d0..13e1c165ef 100644 --- a/lib/core/src/lib/form/components/widgets/text/text.widget.html +++ b/lib/core/src/lib/form/components/widgets/text/text.widget.html @@ -27,10 +27,13 @@ [title]="field.tooltip" (blur)="markAsTouched()"> -
- - -
+ + +
+ + +
+
diff --git a/lib/core/src/lib/form/components/widgets/text/text.widget.spec.ts b/lib/core/src/lib/form/components/widgets/text/text.widget.spec.ts index 45ce5a5fa6..0da9a0f4aa 100644 --- a/lib/core/src/lib/form/components/widgets/text/text.widget.spec.ts +++ b/lib/core/src/lib/form/components/widgets/text/text.widget.spec.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { Component, ViewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormFieldTypes } from '../core/form-field-types'; import { FormFieldModel } from '../core/form-field.model'; @@ -472,4 +473,34 @@ describe('TextWidgetComponent', () => { expect(asterisk.textContent).toEqual('*'); }); }); + + describe('when fieldStatusTemplate is provided', () => { + @Component({ + standalone: true, + template: ` + +
custom status message for {{ widget.field.name }}
+
+ ` + }) + class FieldStatusTemplateTestComponent { + @ViewChild('fieldStatusTemplate', { static: true }) fieldStatusTemplate: TextWidgetComponent['fieldStatusTemplate']; + } + + beforeEach(() => { + const templateFixture = TestBed.createComponent(FieldStatusTemplateTestComponent); + fixture.componentInstance.fieldStatusTemplate = templateFixture.componentInstance.fieldStatusTemplate; + }); + + it('should display custom status template', () => { + widget.field = new FormFieldModel(form, { + id: 'text-id', + name: 'text-name', + type: FormFieldTypes.TEXT + }); + fixture.detectChanges(); + const customStatusMessage = testingUtils.getByCSS('.custom-status-message').nativeElement; + expect(customStatusMessage?.textContent).toBe(`custom status message for ${widget.field.name}`); + }); + }); }); diff --git a/lib/core/src/lib/form/components/widgets/text/text.widget.ts b/lib/core/src/lib/form/components/widgets/text/text.widget.ts index 11f5d99c8d..cf1dbe1859 100644 --- a/lib/core/src/lib/form/components/widgets/text/text.widget.ts +++ b/lib/core/src/lib/form/components/widgets/text/text.widget.ts @@ -17,8 +17,8 @@ /* eslint-disable @angular-eslint/component-selector */ -import { NgIf } from '@angular/common'; -import { Component, OnInit, ViewEncapsulation } from '@angular/core'; +import { NgIf, NgTemplateOutlet } from '@angular/common'; +import { Component, Directive, inject, InjectionToken, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; @@ -27,6 +27,24 @@ import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; import { InputMaskDirective } from './text-mask.component'; +type FieldStatusTemplate = TemplateRef<{ $implicit: WidgetComponent }>; +const FIELD_STATUS_TEMPLATE = new InjectionToken('FIELD_STATUS_TEMPLATE'); + +@Directive({ + selector: '[adf-field-status-template]', + providers: [ + { + provide: FIELD_STATUS_TEMPLATE, + useFactory: (directive: FieldStatusTemplateDirective) => directive.template, + deps: [FieldStatusTemplateDirective] + } + ] +}) +export class FieldStatusTemplateDirective { + @Input('adf-field-status-template') + template?: FieldStatusTemplate; +} + @Component({ selector: 'text-widget', templateUrl: './text.widget.html', @@ -42,13 +60,14 @@ import { InputMaskDirective } from './text-mask.component'; '(invalid)': 'event($event)', '(select)': 'event($event)' }, - imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent, InputMaskDirective], + imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent, InputMaskDirective, NgTemplateOutlet], encapsulation: ViewEncapsulation.None }) export class TextWidgetComponent extends WidgetComponent implements OnInit { mask: string; placeholder: string; isMaskReversed: boolean; + fieldStatusTemplate = inject(FIELD_STATUS_TEMPLATE, { optional: true }); ngOnInit() { if (this.field.params) {