HXIDP-5181 Allow form text fields to render custom field status content (#11523)

This commit is contained in:
Benn Snyder
2026-01-27 08:47:31 -05:00
committed by GitHub
parent 42c2f78baf
commit 15806d7c9f
3 changed files with 61 additions and 8 deletions
@@ -27,10 +27,13 @@
[title]="field.tooltip"
(blur)="markAsTouched()">
</mat-form-field>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
</div>
<ng-container *ngTemplateOutlet="fieldStatusTemplate ?? defaultErrorMessageTemplate; context: { $implicit: this }" />
<ng-template #defaultErrorMessageTemplate>
<div class="adf-error-messages-container">
<error-widget [error]="field.validationSummary" />
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
</div>
</ng-template>
</div>
</div>
@@ -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: `
<ng-template #fieldStatusTemplate let-widget>
<div class="custom-status-message">custom status message for {{ widget.field.name }}</div>
</ng-template>
`
})
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}`);
});
});
});
@@ -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<FieldStatusTemplate>('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) {