AAE-35976 Adding auto required instead of manually handling styles manually (#10956)

* AAE-35976 adding auto-required instead of manually handling required using asterisks inside mat-form-field elements

* AAE-35976 removing hiderequiredmarker as it'll be handled by the form-fields itself

Resolving merge conflicts with develop

* AAE-35976 fixing units

* AAE-35976 adding isVisible condition with the required field

* AAE-35976 removing the method call from html and using the variable instead for conditions
This commit is contained in:
Soumyajit Chakraborty
2025-06-26 18:11:24 +05:30
committed by GitHub
parent 056e4c1429
commit 16f42be08e
26 changed files with 250 additions and 130 deletions

View File

@@ -10,10 +10,8 @@
> >
</div> </div>
<div> <div>
<mat-form-field class="adf-amount-widget__input adf-form-field-input" [hideRequiredMarker]="true" [floatLabel]="placeholder ? 'always' : null"> <mat-form-field class="adf-amount-widget__input adf-form-field-input" [floatLabel]="placeholder ? 'always' : null">
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id" @if ( (field.name || field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{field.name | translate }}</mat-label> }
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></mat-label
>
<span matTextPrefix class="adf-amount-widget__prefix-spacing">{{ currency }}&nbsp;</span> <span matTextPrefix class="adf-amount-widget__prefix-spacing">{{ currency }}&nbsp;</span>
<input <input
matInput matInput
@@ -21,7 +19,7 @@
class="adf-input" class="adf-input"
type="text" type="text"
[id]="field.id" [id]="field.id"
[required]="isRequired()" [required]="field.required && field.isVisible"
[placeholder]="placeholder" [placeholder]="placeholder"
[value]="field.value" [value]="field.value"
[(ngModel)]="field.value" [(ngModel)]="field.value"

View File

@@ -113,14 +113,14 @@ describe('AmountWidgetComponent', () => {
expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy(); expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy();
}); });
it('should be able to display label with asterisk', async () => { it('should be able to display label with asterisk and input field is required', async () => {
fixture.detectChanges(); const formField = await testingUtils.getMatFormField();
await fixture.whenStable(); const formControl = await formField.getControl();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement; expect(formControl.isRequired).toBeTruthy();
expect(asterisk).toBeTruthy(); const inputField = testingUtils.getByCSS('.adf-input').nativeElement;
expect(asterisk.textContent).toEqual('*'); expect(inputField.hasAttribute('required')).toBeTruthy();
}); });
}); });
}); });
@@ -193,7 +193,7 @@ describe('AmountWidgetComponent - rendering', () => {
expect(await field.getPrefixText()).toBe('$'); expect(await field.getPrefixText()).toBe('$');
const widgetLabel = testingUtils.getByCSS('.adf-label').nativeElement; const widgetLabel = testingUtils.getByCSS('.adf-label').nativeElement;
expect(widgetLabel.textContent.trim()).toBe('Test Amount*'); expect(widgetLabel.textContent.trim()).toBe('Test Amount');
expect(widget.field.isValid).toBe(false); expect(widget.field.isValid).toBe(false);
const input = await testingUtils.getMatInput(); const input = await testingUtils.getMatInput();
@@ -229,7 +229,7 @@ describe('AmountWidgetComponent - rendering', () => {
await fixture.whenStable(); await fixture.whenStable();
const widgetLabel = testingUtils.getByCSS('.adf-label').nativeElement; const widgetLabel = testingUtils.getByCSS('.adf-label').nativeElement;
expect(widgetLabel.textContent.trim()).toBe('Test Amount*'); expect(widgetLabel.textContent.trim()).toBe('Test Amount');
const field = await testingUtils.getMatFormField(); const field = await testingUtils.getMatFormField();
expect(await field.getPrefixText()).toBe('£'); expect(await field.getPrefixText()).toBe('£');
@@ -311,6 +311,24 @@ describe('AmountWidgetComponent - rendering', () => {
expect(testingUtils.getByCSS('.adf-left-label-input-container')).toBeNull(); expect(testingUtils.getByCSS('.adf-left-label-input-container')).toBeNull();
expect(testingUtils.getByCSS('.adf-left-label')).toBeNull(); expect(testingUtils.getByCSS('.adf-left-label')).toBeNull();
}); });
it('should be able to display label with manually when left-labels are true', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
id: 'amount-id',
name: 'amount-name',
value: '',
type: FormFieldTypes.AMOUNT,
readOnly: false,
required: true
});
fixture.detectChanges();
await fixture.whenStable();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement;
expect(asterisk).toBeTruthy();
expect(asterisk.textContent).toEqual('*');
});
}); });
}); });

View File

@@ -10,12 +10,17 @@
<div> <div>
<mat-form-field class="adf-date-time-widget adf-form-field-input" <mat-form-field class="adf-date-time-widget adf-form-field-input"
[class.adf-left-label-input-datepicker]="field.leftLabels" [class.adf-left-label-input-datepicker]="field.leftLabels"
[hideRequiredMarker]="true" [floatLabel]="field.placeholder ? 'always' : null"> [floatLabel]="field.placeholder ? 'always' : null">
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id"> @if( (field.name || field?.required) && !field.leftLabels) {
{{ field.name | translate }} ({{ field.dateDisplayFormat }})<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span> <mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }} ({{ field.dateDisplayFormat }})
</mat-label> </mat-label>
}
<input matInput <input matInput
class="adf-input"
[matDatetimepicker]="datetimePicker" [matDatetimepicker]="datetimePicker"
[readonly]="field.readOnly"
[required]="field.required && field.isVisible"
[id]="field.id" [id]="field.id"
[formControl]="datetimeInputControl" [formControl]="datetimeInputControl"
(keydown.enter)="datetimePicker.open()" (keydown.enter)="datetimePicker.open()"

View File

@@ -290,14 +290,6 @@ describe('DateTimeWidgetComponent', () => {
expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy(); expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy();
}); });
it('should be able to display label with asterisk', () => {
fixture.detectChanges();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement;
expect(asterisk).not.toBeNull();
expect(asterisk?.textContent).toEqual('*');
});
it('should be valid when field is hidden with empty value', () => { it('should be valid when field is hidden with empty value', () => {
widget.field.isVisible = false; widget.field.isVisible = false;
fixture.detectChanges(); fixture.detectChanges();
@@ -315,6 +307,16 @@ describe('DateTimeWidgetComponent', () => {
expect(widget.datetimeInputControl.valid).toBeFalse(); expect(widget.datetimeInputControl.valid).toBeFalse();
expect(widget.field.validationSummary.message).toBe('FORM.FIELD.REQUIRED'); expect(widget.field.validationSummary.message).toBe('FORM.FIELD.REQUIRED');
}); });
it('should be able to display label with asterisk and input field is required', async () => {
const formField = await testingUtils.getMatFormField();
const formControl = await formField.getControl();
expect(formControl.isRequired).toBeTruthy();
const inputField = testingUtils.getByCSS('.adf-input').nativeElement;
expect(inputField.hasAttribute('required')).toBeTruthy();
});
}); });
describe('template check', () => { describe('template check', () => {
@@ -504,5 +506,19 @@ describe('DateTimeWidgetComponent', () => {
expect(testingUtils.getByDataAutomationId('adf-date-time-widget-picker')).toBeTruthy(); expect(testingUtils.getByDataAutomationId('adf-date-time-widget-picker')).toBeTruthy();
}); });
it('should be able to display label with asterisk when leftlable is true', () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
id: 'datetime-id',
name: 'datetime-name',
value: '',
type: FormFieldTypes.DATETIME,
readOnly: false,
required: true
});
fixture.detectChanges();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement;
expect(asterisk?.textContent).toEqual('*');
});
}); });
}); });

View File

@@ -12,6 +12,8 @@
[placeholder]="field.placeholder" [placeholder]="field.placeholder"
[min]="minDate" [min]="minDate"
[max]="maxDate" [max]="maxDate"
[required]="field.required && field.isVisible"
[readonly]="field.readOnly"
/> />
<mat-datepicker-toggle matSuffix [for]="datePicker" [disabled]="field.readOnly" /> <mat-datepicker-toggle matSuffix [for]="datePicker" [disabled]="field.readOnly" />
<mat-datepicker #datePicker <mat-datepicker #datePicker

View File

@@ -9,17 +9,14 @@
</div> </div>
<div> <div>
<mat-form-field [hideRequiredMarker]="true" class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null"> <mat-form-field class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id"> @if ( (field.name || field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{ field.name | translate }}</mat-label> }
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
</mat-label>
<input matInput <input matInput
class="adf-input" class="adf-input"
type="text" type="text"
pattern="-?[0-9]*(\.[0-9]*)?" pattern="-?[0-9]*(\.[0-9]*)?"
[id]="field.id" [id]="field.id"
[required]="isRequired()" [required]="field.required && field.isVisible"
[(ngModel)]="field.value" [(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)" (ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly" [disabled]="field.readOnly"

View File

@@ -79,11 +79,14 @@ describe('DecimalComponent', () => {
expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy(); expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy();
}); });
it('should be able to display label with asterisk', async () => { it('should be able to display label with asterisk and input field is required', async () => {
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement; const formField = await testingUtils.getMatFormField();
const formControl = await formField.getControl();
expect(asterisk).toBeTruthy(); expect(formControl.isRequired).toBeTruthy();
expect(asterisk?.textContent).toEqual('*');
const inputField = testingUtils.getByCSS('.adf-input').nativeElement;
expect(inputField.hasAttribute('required')).toBeTruthy();
}); });
}); });
@@ -147,5 +150,22 @@ describe('DecimalComponent', () => {
const adfLeftLabel = testingUtils.getByCSS('.adf-left-label'); const adfLeftLabel = testingUtils.getByCSS('.adf-left-label');
expect(adfLeftLabel).toBeNull(); expect(adfLeftLabel).toBeNull();
}); });
it('should be able to display label with asterisk when leftlabel is true', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
id: 'decimal-id',
name: 'decimal-name',
value: '',
type: FormFieldTypes.DECIMAL,
readOnly: false,
required: true
});
fixture.detectChanges();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement;
expect(asterisk).toBeTruthy();
expect(asterisk?.textContent).toEqual('*');
});
}); });
}); });

View File

@@ -1,23 +1,31 @@
<div class="adf-multiline-text-widget {{ field.className }}" <div
class="adf-multiline-text-widget {{ field.className }}"
[class.adf-invalid]="!field.isValid && isTouched()" [class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"> [class.adf-readonly]="field.readOnly"
<mat-form-field floatPlaceholder="never" [hideRequiredMarker]="true" class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null"> >
<mat-label class="adf-label" [attr.for]="field.id"> <mat-form-field
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span> floatPlaceholder="never"
</mat-label> class="adf-form-field-input"
<textarea matInput [floatLabel]="field.placeholder ? 'always' : null"
>
@if(field.name || field.required) {
<mat-label class="adf-label" [attr.for]="field.id"> {{ field.name | translate }} </mat-label>
}
<textarea
matInput
class="adf-input" class="adf-input"
[cdkTextareaAutosize]="true" [cdkTextareaAutosize]="true"
type="text" type="text"
rows="3" rows="3"
[id]="field.id" [id]="field.id"
[required]="isRequired()" [required]="field.required"
[(ngModel)]="field.value" [(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)" (ngModelChange)="onFieldChanged(field)"
[disabled]="field.readOnly || readOnly" [disabled]="field.readOnly || readOnly"
[placeholder]="field.placeholder" [placeholder]="field.placeholder"
[title]="field.tooltip" [title]="field.tooltip"
(blur)="markAsTouched()"> (blur)="markAsTouched()"
>
</textarea> </textarea>
</mat-form-field> </mat-form-field>
<div *ngIf="field.maxLength > 0" class="adf-multiline-word-counter"> <div *ngIf="field.maxLength > 0" class="adf-multiline-word-counter">
@@ -32,4 +40,3 @@
/> />
</div> </div>
</div> </div>

View File

@@ -64,7 +64,8 @@ describe('MultilineTextWidgetComponentComponent', () => {
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), { widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
type: FormFieldTypes.MULTILINE_TEXT, type: FormFieldTypes.MULTILINE_TEXT,
required: true required: true,
name: 'myField'
}); });
fixture.detectChanges(); fixture.detectChanges();
}); });
@@ -76,11 +77,14 @@ describe('MultilineTextWidgetComponentComponent', () => {
expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy(); expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy();
}); });
it('should be able to display label with asterisk', async () => { it('should be able to display label with asterisk and input field is required', async () => {
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement; const formField = await testingUtils.getMatFormField();
const formControl = await formField.getControl();
expect(asterisk).toBeTruthy(); expect(formControl.isRequired).toBeTruthy();
expect(asterisk.textContent).toEqual('*');
const inputField = testingUtils.getByCSS('.adf-input').nativeElement;
expect(inputField.hasAttribute('required')).toBeTruthy();
}); });
}); });
}); });

View File

@@ -9,16 +9,18 @@
</label> </label>
</div> </div>
<div> <div>
<mat-form-field [hideRequiredMarker]="true" class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null"> <mat-form-field class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id"> @if( (field.name || this.field?.required) && !field.leftLabels) {
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span> <mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }}
</mat-label> </mat-label>
}
<input matInput <input matInput
class="adf-input" class="adf-input"
type="text" type="text"
pattern="-?[0-9]*(\.[0-9]+)?" pattern="-?[0-9]*(\.[0-9]+)?"
[id]="field.id" [id]="field.id"
[required]="isRequired()" [required]="field.required"
[value]="displayValue" [value]="displayValue"
[(ngModel)]="field.value" [(ngModel)]="field.value"
(ngModelChange)="onNumberChange($event)" (ngModelChange)="onNumberChange($event)"

View File

@@ -152,11 +152,14 @@ describe('NumberWidgetComponent', () => {
expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy(); expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy();
}); });
it('should be able to display label with asterisk', async () => { it('should be able to display label with asterisk and input field is required', async () => {
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement; const formField = await testingUtils.getMatFormField();
const formControl = await formField.getControl();
expect(asterisk).toBeTruthy(); expect(formControl.isRequired).toBeTruthy();
expect(asterisk.textContent).toEqual('*');
const inputField = testingUtils.getByCSS('.adf-input').nativeElement;
expect(inputField.hasAttribute('required')).toBeTruthy();
}); });
}); });
@@ -220,5 +223,22 @@ describe('NumberWidgetComponent', () => {
const adfLeftLabel = testingUtils.getByCSS('.adf-left-label'); const adfLeftLabel = testingUtils.getByCSS('.adf-left-label');
expect(adfLeftLabel).toBeNull(); expect(adfLeftLabel).toBeNull();
}); });
it('should be able to display label with asterisk', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
id: 'number-id',
name: 'number-name',
value: '',
type: FormFieldTypes.NUMBER,
readOnly: false,
required: true
});
fixture.detectChanges();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement;
expect(asterisk).toBeTruthy();
expect(asterisk.textContent).toEqual('*');
});
}); });
}); });

View File

@@ -8,15 +8,16 @@
</label> </label>
</div> </div>
<div> <div>
<mat-form-field [hideRequiredMarker]="true" class="adf-form-field-input" [floatLabel]="placeholder ? 'always' : null"> <mat-form-field class="adf-form-field-input" [floatLabel]="placeholder ? 'always' : null">
<mat-label *ngIf="!field.leftLabels" class="adf-label" [attr.for]="field.id"> @if ( (field.name || this.field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span> {{ field.name | translate }}
</mat-label> </mat-label>
}
<input matInput <input matInput
class="adf-input" class="adf-input"
type="text" type="text"
[id]="field.id" [id]="field.id"
[required]="isRequired()" [required]="field.required"
[value]="field.value" [value]="field.value"
[(ngModel)]="field.value" [(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)" (ngModelChange)="onFieldChanged(field)"

View File

@@ -182,14 +182,14 @@ describe('TextWidgetComponent', () => {
expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy(); expect(testingUtils.getByCSS('.adf-invalid')).toBeTruthy();
}); });
it('should be able to display label with asterisk', async () => { it('should be able to display label with asterisk and input field is required', async () => {
fixture.detectChanges(); const formField = await testingUtils.getMatFormField();
await fixture.whenStable(); const formControl = await formField.getControl();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement; expect(formControl.isRequired).toBeTruthy();
expect(asterisk).toBeTruthy(); const inputField = testingUtils.getByCSS('.adf-input').nativeElement;
expect(asterisk.textContent).toEqual('*'); expect(inputField.hasAttribute('required')).toBeTruthy();
}); });
}); });
@@ -437,5 +437,23 @@ describe('TextWidgetComponent', () => {
expect(adfLeftLabel).toBeNull(); expect(adfLeftLabel).toBeNull();
}); });
}); });
it('should be able to display label with asterisk', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
id: 'text-id',
name: 'text-name',
value: '',
type: FormFieldTypes.TEXT,
readOnly: false,
required: true
});
fixture.detectChanges();
await fixture.whenStable();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement;
expect(asterisk).toBeTruthy();
expect(asterisk.textContent).toEqual('*');
});
}); });
}); });

View File

@@ -14,19 +14,20 @@
> >
</div> </div>
<div> <div>
<mat-form-field class="adf-date-widget" [class.adf-left-label-input-datepicker]="field.leftLabels" [hideRequiredMarker]="true"> <mat-form-field class="adf-date-widget adf-form-field-input" [class.adf-left-label-input-datepicker]="field.leftLabels">
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id" @if ( (field.name || field?.required) && !field.leftLabels) {
>{{field.name | translate }} ({{field.dateDisplayFormat}})<span <mat-label class="adf-label" [attr.for]="field.id">
class="adf-asterisk" {{field.name | translate }} ({{field.dateDisplayFormat}})
[style.visibility]="isRequired() ? 'visible' : 'hidden'" </mat-label>
>*</span }
></mat-label>
<input <input
matInput matInput
class="adf-input"
[matDatepicker]="datePicker" [matDatepicker]="datePicker"
[id]="field.id" [id]="field.id"
[formControl]="dateInputControl" [formControl]="dateInputControl"
[placeholder]="field.placeholder" [placeholder]="field.placeholder"
[required]="field.required && field.isVisible"
[min]="minDate" [min]="minDate"
[max]="maxDate" [max]="maxDate"
[title]="field.tooltip" [title]="field.tooltip"

View File

@@ -21,6 +21,9 @@ import { FormFieldModel, FormModel, FormFieldTypes, DEFAULT_DATE_FORMAT } from '
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { DateAdapter } from '@angular/material/core'; import { DateAdapter } from '@angular/material/core';
import { isEqual, subDays, addDays } from 'date-fns'; import { isEqual, subDays, addDays } from 'date-fns';
import { UnitTestingUtils } from '../../../../../../../core/src/lib/testing/unit-testing-utils';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
describe('DateCloudWidgetComponent', () => { describe('DateCloudWidgetComponent', () => {
let widget: DateCloudWidgetComponent; let widget: DateCloudWidgetComponent;
@@ -28,6 +31,8 @@ describe('DateCloudWidgetComponent', () => {
let element: HTMLElement; let element: HTMLElement;
let adapter: DateAdapter<Date>; let adapter: DateAdapter<Date>;
let form: FormModel; let form: FormModel;
let loader: HarnessLoader;
let testingUtils: UnitTestingUtils;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -39,8 +44,10 @@ describe('DateCloudWidgetComponent', () => {
fixture = TestBed.createComponent(DateCloudWidgetComponent); fixture = TestBed.createComponent(DateCloudWidgetComponent);
adapter = fixture.debugElement.injector.get(DateAdapter); adapter = fixture.debugElement.injector.get(DateAdapter);
loader = TestbedHarnessEnvironment.loader(fixture);
widget = fixture.componentInstance; widget = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
}); });
it('should not call onFieldChanged on init', () => { it('should not call onFieldChanged on init', () => {
@@ -445,13 +452,15 @@ describe('DateCloudWidgetComponent', () => {
}); });
}); });
it('should be able to display label with asterisk', () => { it('should be able to display label with asterisk', async () => {
fixture.detectChanges(); fixture.detectChanges();
const formField = await testingUtils.getMatFormField();
const formControl = await formField.getControl();
const asterisk: HTMLElement = element.querySelector('.adf-asterisk'); expect(formControl.isRequired).toBeTruthy();
expect(asterisk).toBeTruthy(); const inputField = await testingUtils.getByCSS('.adf-input').nativeElement;
expect(asterisk.textContent).toEqual('*'); expect(inputField.hasAttribute('required')).toBeTruthy();
}); });
it('should be invalid after user interaction without typing', () => { it('should be invalid after user interaction without typing', () => {

View File

@@ -11,16 +11,19 @@
</div> </div>
<div> <div>
<mat-form-field [hideRequiredMarker]="true"> <mat-form-field class="adf-form-field-input" [floatLabel]="field.placeholder ? 'always' : null">
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id"> @if( (field.name || field?.required) && !field.leftLabels) {
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span> <mat-label class="adf-label" [attr.for]="field.id">
</label> {{ field.name | translate }}
</mat-label>
}
<input matInput <input matInput
class="adf-input" class="adf-input"
type="text" type="text"
data-automation-id="adf-display-external-property-widget" data-automation-id="adf-display-external-property-widget"
[id]="field.id" [id]="field.id"
[formControl]="propertyControl" [formControl]="propertyControl"
[required]="field.required"
> >
<ng-container *ngIf="previewState"> <ng-container *ngIf="previewState">

View File

@@ -25,6 +25,7 @@ import { DisplayExternalPropertyWidgetComponent } from './display-external-prope
import { FormCloudService } from '../../../services/form-cloud.service'; import { FormCloudService } from '../../../services/form-cloud.service';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { UnitTestingUtils } from '../../../../../../../core/src/lib/testing/unit-testing-utils';
describe('DisplayExternalPropertyWidgetComponent', () => { describe('DisplayExternalPropertyWidgetComponent', () => {
let loader: HarnessLoader; let loader: HarnessLoader;
@@ -32,6 +33,7 @@ describe('DisplayExternalPropertyWidgetComponent', () => {
let fixture: ComponentFixture<DisplayExternalPropertyWidgetComponent>; let fixture: ComponentFixture<DisplayExternalPropertyWidgetComponent>;
let element: HTMLElement; let element: HTMLElement;
let formCloudService: FormCloudService; let formCloudService: FormCloudService;
let testingUtils: UnitTestingUtils;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -42,8 +44,10 @@ describe('DisplayExternalPropertyWidgetComponent', () => {
fixture = TestBed.createComponent(DisplayExternalPropertyWidgetComponent); fixture = TestBed.createComponent(DisplayExternalPropertyWidgetComponent);
widget = fixture.componentInstance; widget = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;
loader = TestbedHarnessEnvironment.loader(fixture); loader = TestbedHarnessEnvironment.loader(fixture);
formCloudService = TestBed.inject(FormCloudService); formCloudService = TestBed.inject(FormCloudService);
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
}); });
it('should display initial value', async () => { it('should display initial value', async () => {
@@ -126,11 +130,14 @@ describe('DisplayExternalPropertyWidgetComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should be able to display label with asterisk', () => { it('should be able to display label with asterisk', async () => {
const asterisk = element.querySelector('.adf-asterisk'); const formField = await testingUtils.getMatFormField();
const formControl = await formField.getControl();
expect(asterisk).toBeTruthy(); expect(formControl.isRequired).toBeTruthy();
expect(asterisk?.textContent).toEqual('*');
const inputField = await testingUtils.getByCSS('.adf-input').nativeElement;
expect(inputField.hasAttribute('required')).toBeTruthy();
}); });
}); });

View File

@@ -10,10 +10,8 @@
</label> </label>
</div> </div>
<div> <div>
<mat-form-field> <mat-form-field class="adf-form-field-input">
<mat-label *ngIf="!field.leftLabels" class="adf-label" [attr.for]="field.id"> @if ( (field.name || this.field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{ field.name | translate }}</mat-label> }
{{ field.name | translate }}
</mat-label>
<mat-select <mat-select
class="adf-select" class="adf-select"
[formControl]="dropdownControl" [formControl]="dropdownControl"
@@ -22,7 +20,8 @@
[title]="field.tooltip" [title]="field.tooltip"
panelClass="adf-select-filter" panelClass="adf-select-filter"
[multiple]="field.hasMultipleValues" [multiple]="field.hasMultipleValues"
[required]="isRequired()" [disabled]="field.readOnly"
[required]="field.required "
> >
<adf-select-filter-input *ngIf="showInputFilter" (change)="filter$.next($event)" /> <adf-select-filter-input *ngIf="showInputFilter" (change)="filter$.next($event)" />
@@ -30,7 +29,7 @@
<mat-option id="readonlyOption" *ngIf="isReadOnlyType" [value]="field.value">{{field.value}}</mat-option> <mat-option id="readonlyOption" *ngIf="isReadOnlyType" [value]="field.value">{{field.value}}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<div *ngIf="!previewState && !field.readOnly"> <div class="adf-error-messages-container" *ngIf="!previewState && !field.readOnly">
<error-widget <error-widget
class="adf-dropdown-required-message" class="adf-dropdown-required-message"
*ngIf="showRequiredMessage" *ngIf="showRequiredMessage"

View File

@@ -38,6 +38,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatSelectHarness } from '@angular/material/select/testing'; import { MatSelectHarness } from '@angular/material/select/testing';
import { DebugElement } from '@angular/core'; import { DebugElement } from '@angular/core';
import { FormUtilsService } from '../../../services/form-utils.service'; import { FormUtilsService } from '../../../services/form-utils.service';
import { UnitTestingUtils } from '../../../../../../../core/src/public-api';
describe('DropdownCloudWidgetComponent', () => { describe('DropdownCloudWidgetComponent', () => {
let formService: FormService; let formService: FormService;
@@ -47,6 +48,7 @@ describe('DropdownCloudWidgetComponent', () => {
let fixture: ComponentFixture<DropdownCloudWidgetComponent>; let fixture: ComponentFixture<DropdownCloudWidgetComponent>;
let element: HTMLElement; let element: HTMLElement;
let loader: HarnessLoader; let loader: HarnessLoader;
let testingUtils: UnitTestingUtils;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -60,6 +62,7 @@ describe('DropdownCloudWidgetComponent', () => {
formCloudService = TestBed.inject(FormCloudService); formCloudService = TestBed.inject(FormCloudService);
formUtilsService = TestBed.inject(FormUtilsService); formUtilsService = TestBed.inject(FormUtilsService);
loader = TestbedHarnessEnvironment.loader(fixture); loader = TestbedHarnessEnvironment.loader(fixture);
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
}); });
afterEach(() => fixture.destroy()); afterEach(() => fixture.destroy());
@@ -330,22 +333,15 @@ describe('DropdownCloudWidgetComponent', () => {
describe('when is required', () => { describe('when is required', () => {
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), { widget.field = new FormFieldModel(new FormModel({ taskId: '<id>', leftLabels: true }), {
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
required: true required: true
}); });
}); });
it('should be able to display label with asterisk when left-label is present', () => { it('should be able to display label with asterisk when left-label is present', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false, leftLabels: true }), {
id: 'dropdown-id',
name: 'option list',
type: FormFieldTypes.DROPDOWN,
options: filterOptionList
});
fixture.detectChanges(); fixture.detectChanges();
const asterisk = testingUtils.getByCSS('.adf-asterisk').nativeElement;
const asterisk: HTMLElement = element.querySelector('.adf-asterisk');
expect(asterisk).toBeTruthy(); expect(asterisk).toBeTruthy();
expect(asterisk.textContent).toEqual('*'); expect(asterisk.textContent).toEqual('*');

View File

@@ -17,7 +17,7 @@
[validate]="validate" [validate]="validate"
[roles]="roles" [roles]="roles"
[searchGroupsControl]="search" [searchGroupsControl]="search"
[required]="isRequired()" [required]="field.required"
(changedGroups)="onChangedGroup($event)" (changedGroups)="onChangedGroup($event)"
[preSelectGroups]="preSelectGroup" [preSelectGroups]="preSelectGroup"
(blur)="markAsTouched()" (blur)="markAsTouched()"

View File

@@ -76,13 +76,13 @@ describe('GroupCloudWidgetComponent', () => {
describe('when is required', () => { describe('when is required', () => {
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), { widget.field = new FormFieldModel(new FormModel({ taskId: '<id>', leftLabels: true }), {
type: FormFieldTypes.GROUP, type: FormFieldTypes.GROUP,
required: true required: true
}); });
}); });
it('should be able to display label with asterisk', async () => { it('should be able to display label with asterisk when leftLabel is tru', async () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();

View File

@@ -12,7 +12,7 @@
[readOnly]="field.readOnly" [readOnly]="field.readOnly"
[validate]="validate" [validate]="validate"
[searchUserCtrl]="search" [searchUserCtrl]="search"
[required]="isRequired()" [required]="field.required"
(changedUsers)="onChangedUser($event)" (changedUsers)="onChangedUser($event)"
[roles]="roles" [roles]="roles"
[mode]="mode" [mode]="mode"

View File

@@ -104,7 +104,7 @@ describe('PeopleCloudWidgetComponent', () => {
describe('when is required', () => { describe('when is required', () => {
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), { widget.field = new FormFieldModel(new FormModel({ taskId: '<id>', leftLabels: true }), {
type: FormFieldTypes.PEOPLE, type: FormFieldTypes.PEOPLE,
required: true required: true
}); });

View File

@@ -1,16 +1,13 @@
<form> <form>
<mat-form-field class="adf-cloud-group" [class.adf-invalid]="hasError() && isDirty()"> <mat-form-field class="adf-cloud-group adf-form-field-input" [class.adf-invalid]="hasError() && isDirty()">
<mat-label> @if (label || required) { <mat-label><span>{{label}}</span></mat-label> }
<span>{{label}}</span> <mat-chip-grid [required]="required" #groupChipList data-automation-id="adf-cloud-group-chip-list">
<span class="adf-asterisk" [style.visibility]="required ? 'visible' : 'hidden'">*</span>
</mat-label>
<mat-chip-grid #groupChipList data-automation-id="adf-cloud-group-chip-list">
<mat-chip-row <mat-chip-row
*ngFor="let group of selectedGroups" *ngFor="let group of selectedGroups"
[removable]="!(group.readonly)" [removable]="!(group.readonly)"
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name" [attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
(removed)="onRemove(group)" (removed)="onRemove(group)"
[disabled]="isReadonly() || isValidationLoading()" [disabled]="readOnly || isValidationLoading()"
title="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}"> title="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}">
{{group.name}} {{group.name}}
<mat-icon <mat-icon
@@ -19,7 +16,7 @@
cancel cancel
</mat-icon> </mat-icon>
</mat-chip-row> </mat-chip-row>
<input [disabled]="isReadonly()" matInput <input [disabled]="readOnly || isValidationLoading()" matInput
[formControl]="searchGroupsControl" [formControl]="searchGroupsControl"
[matAutocomplete]="auto" [matAutocomplete]="auto"
[matChipInputFor]="groupChipList" [matChipInputFor]="groupChipList"

View File

@@ -2,16 +2,15 @@
<mat-form-field <mat-form-field
[subscriptSizing]="formFieldSubscriptSizing" [subscriptSizing]="formFieldSubscriptSizing"
[floatLabel]="'auto'" [floatLabel]="'auto'"
class="adf-people-cloud" class="adf-people-cloud adf-form-field-input"
[class.adf-invalid]="hasError() && isDirty()" [class.adf-invalid]="hasError() && isDirty()"
> >
<mat-label *ngIf="!title"> <mat-label *ngIf="!title">
<span>{{label}}</span> <span>{{label}}</span>
<span class="adf-asterisk" [style.visibility]="required ? 'visible' : 'hidden'">*</span>
</mat-label> </mat-label>
<mat-label *ngIf="title">{{ title | translate }}</mat-label> <mat-label *ngIf="title">{{ title | translate }}</mat-label>
<mat-chip-grid #userMultipleChipList data-automation-id="adf-cloud-people-chip-list"> <mat-chip-grid [required]="required" #userMultipleChipList data-automation-id="adf-cloud-people-chip-list">
<mat-chip-row <mat-chip-row
*ngFor="let user of selectedUsers" *ngFor="let user of selectedUsers"
[removable]="!user.readonly" [removable]="!user.readonly"
@@ -38,6 +37,7 @@
[matChipInputFor]="userMultipleChipList" [matChipInputFor]="userMultipleChipList"
[required]="required" [required]="required"
[placeholder]="placeholder" [placeholder]="placeholder"
[disabled]="isReadonly() || isValidationLoading()"
(focus)="setFocus(true)" (focus)="setFocus(true)"
(blur)="setFocus(false); markAsTouched()" (blur)="setFocus(false); markAsTouched()"
class="adf-cloud-input" class="adf-cloud-input"

View File

@@ -331,7 +331,7 @@ describe('StartFormComponent', () => {
expect(dateElement).toBeDefined(); expect(dateElement).toBeDefined();
expect(selectElement).toBeDefined(); expect(selectElement).toBeDefined();
expect(translate.instant(inputLabelElement.textContent.trim())).toBe('ClientName*'); expect(translate.instant(inputLabelElement.textContent.trim())).toBe('ClientName');
expect(translate.instant(dateLabelElement.innerText)).toBe('BillDate (D-M-YYYY)'); expect(translate.instant(dateLabelElement.innerText)).toBe('BillDate (D-M-YYYY)');
expect(translate.instant(selectLabelElement.innerText)).toBe('ClaimType'); expect(translate.instant(selectLabelElement.innerText)).toBe('ClaimType');
}); });