mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
Improvement/AAE-43974 Refactoring form fields (#11945)
* AAE-43974 Refactoring form fields with mat-error * AAE-43974 Removed adf-error redundant class from all available places * AAE-43974 Followed code flow syntax * AAE-43974 Refactored based on review comments * AAE-43974 Added dummy test lable * AAE-43974 Added dummy error message for amount field * AAE-43974 Refactored multiline widget based on reviewer's comment * AAE-43974 Error icon style added by mixins * AAE-43974 Missing Conditions added * AAE-43974 Added Missing conditions * AAE-43974 Consistent conditions added and dummy error message added * AAE-43974 Added subscriptsizing dynamic for testing * AAE-43974 Reverted Subscriptsizing * AAE-43974 Added spacing between form fields in mobile view * AAE-43974 Dummy error message changed * AAE-43974 Changed error icon allignment for testing * AAE-43974 Added dummy error message * AAE-43974 Added form field gap in mobile view and dummy erro message * AAE-43974 Refactored based on review coemments and changed the error icon allignment * AAE-43974 Fixed the mixin path * AAE-43974 Removed dummy error message for amount widget * AAE-43974 Added adf-error-text class to mat-error for e2e fix * AAE-43974 adf-error-text class added inside mat-error * AAE-43974 Whitespace issue resolved * AAE-43974 Whiespace issue fix * AAE-43974 Added context pushing logic in text widget * AAE-43974 Added margin-bottom for regression fix * AAE-43974 Trying with different margin-bottom * AAE-43974 Testing regression issue * AAE-43974 Testing for regression failure * AAE-43974 Testing Regression failures * AAE-43974 Test Regression failure * AAE-43974 Testing multiline Regression failure * AAE-43974 Testing fix regarding regression failure related to multiline-text widget * AAE-43974 Test Regression failure for multiline-text widget * AAE-43974 Testing regression failure for multiline-text * AAE-43974 Testing regression failure for multi-line * AAE-43974 Testing regression failure * AAE-43974 Testing Regression failure * AAE-43974 Testing regression failure * AAE-43974 Removed the commented code * [ci:force] re-trigger CI --------- Co-authored-by: Ehsan Rezaei <ehsan.rezaei@hyland.com>
This commit is contained in:
co-authored by
Ehsan Rezaei
parent
23f0392c12
commit
b0dc85422c
@@ -6,13 +6,17 @@
|
||||
<label class="adf-label" [attr.for]="field.id"
|
||||
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
|
||||
>
|
||||
<mat-form-field>
|
||||
<mat-form-field class="adf-form-field-input">
|
||||
<mat-select class="adf-select" [id]="field.id" [formControl]="dropdownControl">
|
||||
<mat-option *ngFor="let opt of field.options" [value]="opt" [id]="opt.id">{{opt.name}}</mat-option>
|
||||
<mat-option id="readonlyOption" *ngIf="dropdownControl.disabled" [value]="field.value">{{field.value}}</mat-option>
|
||||
</mat-select>
|
||||
@if (!isReadOnlyField && dropdownControl.touched && (field.validationSummary?.message || dropdownControl.hasError('required'))) {
|
||||
<mat-error data-automation-id="adf-dropdown-error">
|
||||
<mat-icon class="adf-error-icon">error_outline</mat-icon>
|
||||
<span class="adf-error-text"
|
||||
>@if (field.validationSummary?.message) {{{ field.validationSummary.message | translate }}} @else {{{ 'FORM.FIELD.REQUIRED' | translate }}}</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<ng-container *ngIf="!isReadOnlyField && dropdownControl.touched">
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@use '../../../styles/mixins' as mixins;
|
||||
|
||||
.adf {
|
||||
&-dropdown-widget {
|
||||
width: 100%;
|
||||
@@ -12,3 +14,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adf-form-field-input .adf-error-icon {
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ describe('DropdownWidgetComponent', () => {
|
||||
widget.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(element.querySelector('.adf-dropdown-required-message')).toBeNull();
|
||||
expect(element.querySelector('[data-automation-id="adf-dropdown-error"]')).toBeNull();
|
||||
});
|
||||
|
||||
it('should NOT preserve empty option when loading fields', () => {
|
||||
|
||||
@@ -18,19 +18,12 @@
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import {
|
||||
FormService,
|
||||
FormFieldOption,
|
||||
WidgetComponent,
|
||||
ErrorWidgetComponent,
|
||||
ErrorMessageModel,
|
||||
FormFieldModel,
|
||||
ReactiveFormWidget
|
||||
} from '@alfresco/adf-core';
|
||||
import { FormService, FormFieldOption, WidgetComponent, ErrorMessageModel, FormFieldModel, ReactiveFormWidget } from '@alfresco/adf-core';
|
||||
import { ProcessDefinitionService } from '../../services/process-definition.service';
|
||||
import { TaskFormService } from '../../services/task-form.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { AbstractControl, FormControl, ReactiveFormsModule, ValidationErrors, ValidatorFn } from '@angular/forms';
|
||||
import { filter } from 'rxjs/operators';
|
||||
@@ -39,7 +32,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component({
|
||||
selector: 'dropdown-widget',
|
||||
imports: [CommonModule, TranslatePipe, MatFormFieldModule, MatSelectModule, ReactiveFormsModule, ErrorWidgetComponent],
|
||||
imports: [CommonModule, TranslatePipe, MatFormFieldModule, MatSelectModule, ReactiveFormsModule, MatIconModule],
|
||||
templateUrl: './dropdown.widget.html',
|
||||
styleUrls: ['./dropdown.widget.scss'],
|
||||
host: {
|
||||
|
||||
+7
-2
@@ -48,7 +48,12 @@
|
||||
<span id="adf-group-label-name">{{item.name}}</span>
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
@if (field.validationSummary?.message || (isInvalidFieldRequired() && isTouched())) {
|
||||
<mat-error>
|
||||
<mat-icon class="adf-error-icon">error_outline</mat-icon>
|
||||
<span class="adf-error-text"
|
||||
>@if (field.validationSummary?.message) {{{ field.validationSummary.message | translate }}} @else {{{ 'FORM.FIELD.REQUIRED' | translate }}}</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
|
||||
</div>
|
||||
|
||||
+6
@@ -1,3 +1,5 @@
|
||||
@use '../../../styles/mixins' as mixins;
|
||||
|
||||
.adf {
|
||||
&-group-widget {
|
||||
width: 100%;
|
||||
@@ -14,3 +16,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adf-group-widget-field .adf-error-icon {
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
|
||||
+1
-2
@@ -18,7 +18,7 @@
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { Component, ElementRef, inject, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ErrorWidgetComponent, GroupModel, WidgetComponent } from '@alfresco/adf-core';
|
||||
import { GroupModel, WidgetComponent } from '@alfresco/adf-core';
|
||||
import { catchError, debounceTime, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';
|
||||
import { merge, of } from 'rxjs';
|
||||
import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
|
||||
@@ -40,7 +40,6 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
MatInputModule,
|
||||
ReactiveFormsModule,
|
||||
MatAutocompleteModule,
|
||||
ErrorWidgetComponent,
|
||||
MatChipsModule,
|
||||
MatIconModule
|
||||
],
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
<label class="adf-label" [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label>
|
||||
<mat-form-field
|
||||
class="adf-people-widget-field">
|
||||
<mat-chip-grid #chipGrid [attr.aria-label]="'ADF_PROCESS_LIST.START_PROCESS.FORM.LABEL.SELECTED_PEOPLE' | translate">
|
||||
<mat-chip-grid #chipGrid [attr.aria-label]="'ADF_PROCESS_LIST.START_PROCESS.FORM.LABEL.SELECTED_PEOPLE' | translate"
|
||||
[ngModel]="selectedUsers" [errorStateMatcher]="errorStateMatcher">
|
||||
<mat-chip-row
|
||||
*ngFor="let user of selectedUsers"
|
||||
(removed)="onRemove(user)"
|
||||
@@ -47,7 +48,12 @@
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
@if (field.validationSummary?.message || (isInvalidFieldRequired() && isTouched())) {
|
||||
<mat-error>
|
||||
<mat-icon class="adf-error-icon">error_outline</mat-icon>
|
||||
<span class="adf-error-text"
|
||||
>@if (field.validationSummary?.message) {{{ field.validationSummary.message | translate }}} @else {{{ 'FORM.FIELD.REQUIRED' | translate }}}</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@use '../../../styles/mixins' as mixins;
|
||||
|
||||
.adf {
|
||||
&-people-widget {
|
||||
width: 100%;
|
||||
@@ -59,3 +61,7 @@
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-people-widget-field .adf-error-icon {
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
|
||||
@@ -368,17 +368,13 @@ describe('PeopleWidgetComponent', () => {
|
||||
});
|
||||
|
||||
it('should show an error message if the user is invalid', fakeAsync(() => {
|
||||
const peopleHTMLElement = element.querySelector<HTMLInputElement>('input');
|
||||
peopleHTMLElement.focus();
|
||||
peopleHTMLElement.value = 'K';
|
||||
peopleHTMLElement.dispatchEvent(new Event('keyup'));
|
||||
peopleHTMLElement.dispatchEvent(new Event('input'));
|
||||
|
||||
widget.searchTerm.setValue('K');
|
||||
tick(300);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(element.querySelector('.adf-error-text')).not.toBeNull();
|
||||
expect(element.querySelector('.adf-error-text').textContent).toContain('FORM.FIELD.VALIDATOR.INVALID_VALUE');
|
||||
const errorText = element.querySelector('.adf-error-text');
|
||||
expect(errorText).not.toBeNull();
|
||||
expect(errorText.textContent).toContain('FORM.FIELD.VALIDATOR.INVALID_VALUE');
|
||||
}));
|
||||
|
||||
it('should show the people if the typed result match', fakeAsync(() => {
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { ErrorWidgetComponent, InitialUsernamePipe, WidgetComponent } from '@alfresco/adf-core';
|
||||
import { InitialUsernamePipe, WidgetComponent } from '@alfresco/adf-core';
|
||||
import { Component, ElementRef, EventEmitter, inject, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
|
||||
import { FormsModule, ReactiveFormsModule, UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { Observable, of } from 'rxjs';
|
||||
@@ -41,10 +42,10 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
MatInputModule,
|
||||
MatChipsModule,
|
||||
MatIconModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatAutocompleteModule,
|
||||
InitialUsernamePipe,
|
||||
ErrorWidgetComponent
|
||||
InitialUsernamePipe
|
||||
],
|
||||
templateUrl: './people.widget.html',
|
||||
styleUrls: ['./people.widget.scss'],
|
||||
@@ -93,8 +94,10 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
|
||||
})
|
||||
);
|
||||
public peopleProcessService = inject(PeopleProcessService);
|
||||
errorStateMatcher: ErrorStateMatcher;
|
||||
|
||||
ngOnInit() {
|
||||
this.initErrorStateMatcher();
|
||||
if (this.field) {
|
||||
if (this.field.value) {
|
||||
Array.isArray(this.field.value) ? this.selectedUsers.push(...this.field.value) : this.selectedUsers.push(this.field.value);
|
||||
@@ -163,6 +166,13 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
|
||||
this.searchTerm.setValue('');
|
||||
}
|
||||
|
||||
private initErrorStateMatcher(): void {
|
||||
this.errorStateMatcher = {
|
||||
isErrorState: (_control: UntypedFormControl | null, _form: FormGroupDirective | NgForm | null): boolean =>
|
||||
!!this.field.validationSummary?.message || (this.isInvalidFieldRequired() && this.isTouched())
|
||||
};
|
||||
}
|
||||
|
||||
isUserAlreadySelected(user: LightUserRepresentation): boolean {
|
||||
if (this.selectedUsers?.length > 0) {
|
||||
const result = this.selectedUsers.find((selectedUser) => selectedUser.id === user.id);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[class.adf-invalid]="!field.isValid"
|
||||
[class.adf-readonly]="field.readOnly"
|
||||
id="typehead-div">
|
||||
<mat-form-field>
|
||||
<mat-form-field class="adf-form-field-input">
|
||||
<label class="adf-label" [attr.for]="field.id">{{field.name | translate }}</label>
|
||||
<input matInput class="adf-input"
|
||||
type="text"
|
||||
@@ -15,15 +15,20 @@
|
||||
[disabled]="field.readOnly"
|
||||
data-automation-id="adf-typeahed-search-input"
|
||||
placeholder="{{field.placeholder}}"
|
||||
[errorStateMatcher]="errorStateMatcher"
|
||||
[matAutocomplete]="auto">
|
||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="onItemSelect($event.option.value)">
|
||||
<mat-option *ngFor="let item of options; let i = index" id="adf-typeahed-widget-user-{{i}}" [value]="item">
|
||||
<span id="adf-typeahed-label-name">{{item.name}}</span>
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
@if (field.validationSummary?.message || isInvalidFieldRequired()) {
|
||||
<mat-error>
|
||||
<mat-icon class="adf-error-icon">error_outline</mat-icon>
|
||||
<span class="adf-error-text"
|
||||
>@if (field.validationSummary?.message) {{{ field.validationSummary.message | translate }}} @else {{{ 'FORM.FIELD.REQUIRED' | translate }}}</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@use '../../../styles/mixins' as mixins;
|
||||
|
||||
.adf {
|
||||
&-typeahead-widget-container {
|
||||
position: relative;
|
||||
@@ -8,3 +10,7 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-form-field-input .adf-error-icon {
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ import { TypeaheadWidgetComponent } from './typeahead.widget';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { TaskFormService } from '../../services/task-form.service';
|
||||
import { ProcessDefinitionService } from '../../services/process-definition.service';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatFormFieldHarness } from '@angular/material/form-field/testing';
|
||||
|
||||
describe('TypeaheadWidgetComponent', () => {
|
||||
let widget: TypeaheadWidgetComponent;
|
||||
@@ -181,6 +184,7 @@ describe('TypeaheadWidgetComponent', () => {
|
||||
let typeaheadWidgetComponent: TypeaheadWidgetComponent;
|
||||
let fixture: ComponentFixture<TypeaheadWidgetComponent>;
|
||||
let element: HTMLElement;
|
||||
let loader: HarnessLoader;
|
||||
let stubProcessDefinitionService;
|
||||
const fakeOptionList: FormFieldOption[] = [
|
||||
{
|
||||
@@ -198,6 +202,7 @@ describe('TypeaheadWidgetComponent', () => {
|
||||
fixture = TestBed.createComponent(TypeaheadWidgetComponent);
|
||||
typeaheadWidgetComponent = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -295,15 +300,16 @@ describe('TypeaheadWidgetComponent', () => {
|
||||
typeaheadWidgetComponent.value = 'Fake Name';
|
||||
typeaheadWidgetComponent.field.value = 'Fake Name';
|
||||
typeaheadWidgetComponent.field.options = fakeOptionList;
|
||||
expect(element.querySelector('.adf-error-text')).toBeNull();
|
||||
const keyboardEvent = new KeyboardEvent('keypress');
|
||||
typeaheadWidgetComponent.onKeyUp(keyboardEvent);
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-error-text')).not.toBeNull();
|
||||
expect(element.querySelector('.adf-error-text').textContent).toContain('FORM.FIELD.VALIDATOR.INVALID_VALUE');
|
||||
const formField = await loader.getHarness(MatFormFieldHarness);
|
||||
const errors = await formField.getTextErrors();
|
||||
expect(errors.length).toBeGreaterThan(0);
|
||||
expect(errors[0]).toContain('FORM.FIELD.VALIDATOR.INVALID_VALUE');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -17,21 +17,23 @@
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { FormFieldOption, WidgetComponent, ErrorWidgetComponent } from '@alfresco/adf-core';
|
||||
import { FormFieldOption, WidgetComponent } from '@alfresco/adf-core';
|
||||
import { ENTER, ESCAPE } from '@angular/cdk/keycodes';
|
||||
import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormsModule, FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { TaskFormService } from '../../services/task-form.service';
|
||||
import { ProcessDefinitionService } from '../../services/process-definition.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
@Component({
|
||||
selector: 'typeahead-widget',
|
||||
imports: [CommonModule, TranslatePipe, MatFormFieldModule, FormsModule, MatAutocompleteModule, ErrorWidgetComponent, MatInputModule],
|
||||
imports: [CommonModule, TranslatePipe, MatFormFieldModule, FormsModule, MatAutocompleteModule, MatInputModule, MatIconModule],
|
||||
templateUrl: './typeahead.widget.html',
|
||||
styleUrls: ['./typeahead.widget.scss'],
|
||||
host: {
|
||||
@@ -52,11 +54,13 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit
|
||||
value: string;
|
||||
oldValue: string;
|
||||
options: FormFieldOption[] = [];
|
||||
errorStateMatcher: ErrorStateMatcher;
|
||||
|
||||
private readonly taskFormService = inject(TaskFormService);
|
||||
private readonly processDefinitionService = inject(ProcessDefinitionService);
|
||||
|
||||
ngOnInit() {
|
||||
this.initErrorStateMatcher();
|
||||
if (this.field.form.taskId && this.field.restUrl) {
|
||||
this.getValuesByTaskId();
|
||||
} else if (this.field.form.processDefinitionId && this.field.restUrl) {
|
||||
@@ -153,4 +157,11 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit
|
||||
isReadOnlyType(): boolean {
|
||||
return this.field.type === 'readonly';
|
||||
}
|
||||
|
||||
private initErrorStateMatcher(): void {
|
||||
this.errorStateMatcher = {
|
||||
isErrorState: (_control: UntypedFormControl | null, _form: FormGroupDirective | NgForm | null): boolean =>
|
||||
!!this.field.validationSummary?.message || this.isInvalidFieldRequired()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
@mixin adf-error-icon {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
+18
-15
@@ -11,12 +11,12 @@
|
||||
matInput
|
||||
id="name_id"
|
||||
formControlName="name">
|
||||
<mat-error *ngIf="nameController.hasError('required') || nameController.hasError('whitespace')">
|
||||
{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.REQUIRED' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="nameController.hasError('maxlength')">
|
||||
{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.MAXIMUM_LENGTH' | translate : { characters : maxTaskNameLength } }}
|
||||
</mat-error>
|
||||
@if (nameController.invalid) {
|
||||
<mat-error>
|
||||
<span class="adf-error-text"
|
||||
>@if (nameController.hasError('required') || nameController.hasError('whitespace')) {{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.REQUIRED' | translate }}} @else if (nameController.hasError('maxlength')) {{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.MAXIMUM_LENGTH' | translate : { characters : maxTaskNameLength } }}}</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="adf-task-description">
|
||||
@@ -28,18 +28,21 @@
|
||||
id="description_id"
|
||||
formControlName="description">
|
||||
</textarea>
|
||||
<mat-error *ngIf="descriptionController.hasError('whitespace')">
|
||||
{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.MESSAGE' | translate }}
|
||||
</mat-error>
|
||||
@if (descriptionController.hasError('whitespace')) {
|
||||
<mat-error>
|
||||
<span class="adf-error-text">{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.MESSAGE' | translate }}</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="adf-input-row">
|
||||
<mat-form-field>
|
||||
<mat-form-field class="adf-form-field-input">
|
||||
<input
|
||||
matInput
|
||||
(keyup)="onDateChanged($any($event).srcElement.value)"
|
||||
(dateInput)="onDateChanged($any($event).value)"
|
||||
[matDatepicker]="taskDatePicker"
|
||||
[errorStateMatcher]="dateErrorStateMatcher"
|
||||
placeholder="{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.DATE'|translate}}"
|
||||
id="date_id">
|
||||
<mat-datepicker-toggle
|
||||
@@ -48,12 +51,12 @@
|
||||
<mat-datepicker
|
||||
#taskDatePicker
|
||||
[touchUi]="true" />
|
||||
<div class="adf-error-text-container">
|
||||
<div *ngIf="dateError">
|
||||
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
|
||||
@if (dateError) {
|
||||
<mat-error>
|
||||
<mat-icon class="adf-error-icon">warning</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<span class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</span>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<people-widget
|
||||
(peopleSelected)="setAssigneeId($event)"
|
||||
|
||||
+5
-5
@@ -1,4 +1,5 @@
|
||||
@use '../../../styles/flex' as flex;
|
||||
@use '../../../styles/mixins' as mixins;
|
||||
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
.adf-new-task-heading {
|
||||
@@ -112,11 +113,6 @@ adf-start-task {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&-error-icon {
|
||||
font: var(--mat-sys-body-medium);
|
||||
color: var(--mat-sys-error);
|
||||
}
|
||||
|
||||
&-label {
|
||||
color: var(--mat-sys-outline);
|
||||
}
|
||||
@@ -140,3 +136,7 @@ adf-start-task {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adf-form-field-input .adf-error-icon {
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
|
||||
+5
-1
@@ -17,7 +17,7 @@
|
||||
|
||||
import { ADF_DATE_FORMATS, AdfDateFnsAdapter, DateFnsUtils, FormFieldModel, FormModel } from '@alfresco/adf-core';
|
||||
import { Component, DestroyRef, EventEmitter, inject, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
||||
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
|
||||
import { DateAdapter, ErrorStateMatcher, MAT_DATE_FORMATS } from '@angular/material/core';
|
||||
import { EMPTY, Observable } from 'rxjs';
|
||||
import { Form } from '../../models/form.model';
|
||||
import { TaskListService } from '../../services/tasklist.service';
|
||||
@@ -96,6 +96,10 @@ export class StartTaskComponent implements OnInit {
|
||||
maxTaskNameLength: number = MAX_LENGTH;
|
||||
loading = false;
|
||||
|
||||
dateErrorStateMatcher: ErrorStateMatcher = {
|
||||
isErrorState: () => this.dateError
|
||||
};
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
Reference in New Issue
Block a user