mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-1351] [GroupCloudComponent] Validate pre-selected groups (#5353)
* * Added an input flag to validate preselected groups. * Modified demo shell groups page. * * Added unit tests to the recent changes. * * Fixed comments
This commit is contained in:
committed by
Maurizio Vitale
parent
12d068c228
commit
68df1ad440
@@ -308,7 +308,11 @@
|
||||
"APP_NAME": "Application Name",
|
||||
"APP_FILTER_MODE": "Filter by application name",
|
||||
"ROLE_FILTER_MODE": "Filter by role",
|
||||
"PRESELECT_VALIDATION": "Preselect validation"
|
||||
"PRESELECT_VALIDATION": "Preselect validation",
|
||||
"ALL_SELECTED_USERS": "All Selected Users",
|
||||
"ALL_SELECTED_GROUPS": "All Selected Groups",
|
||||
"INVALID_USERS": "Invalid Users",
|
||||
"INVALID_GROUPS": "Invalid Groups"
|
||||
},
|
||||
"SETTINGS_CLOUD": {
|
||||
"MULTISELECTION": "Multiselection",
|
||||
|
@@ -40,16 +40,29 @@
|
||||
[appName]="peopleAppName"
|
||||
[roles]="peopleRoles"
|
||||
[title]="'ADF_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
|
||||
[mode]="peopleMode"></adf-cloud-people>
|
||||
[mode]="peopleMode"
|
||||
(selectUser)="onSelectUser($event)"
|
||||
(warning)="onUsersWarning($event)"></adf-cloud-people>
|
||||
</div>
|
||||
|
||||
<div class="app-people-list" *ngIf="canShowPeopleList()">
|
||||
<h4>{{ 'PEOPLE_GROUPS_CLOUD.ALL_SELECTED_USERS' | translate }}</h4>
|
||||
<mat-list role="list">
|
||||
<mat-list-item *ngFor="let item of preSelectUsers" role="listitem">
|
||||
<mat-icon mat-list-icon>person</mat-icon>
|
||||
{{ item?.firstName }} {{ item?.lastName }}
|
||||
{{item | fullName}}
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
<div *ngIf="invalidUsers.length > 0">
|
||||
<h4>{{ 'PEOPLE_GROUPS_CLOUD.INVALID_USERS' | translate }} <mat-icon>warning</mat-icon> </h4>
|
||||
<mat-list role="list">
|
||||
<mat-list-item *ngFor="let invalidUser of invalidUsers" role="listitem">
|
||||
<mat-icon mat-list-icon>person</mat-icon>
|
||||
{{invalidUser | fullName}}
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -86,19 +99,39 @@
|
||||
<mat-label>Preselect: {{ DEFAULT_GROUP_PLACEHOLDER }}</mat-label>
|
||||
<input matInput (input)="setGroupsPreselectValue($event)" data-automation-id="app-group-preselect-input" />
|
||||
</mat-form-field>
|
||||
<mat-checkbox class="app-group-preselect-validation" (change)="onChangeGroupValidation($event)">{{
|
||||
'PEOPLE_GROUPS_CLOUD.PRESELECT_VALIDATION' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
<div>
|
||||
<adf-cloud-group [mode]="groupMode" [roles]="groupRoles" [appName]="groupAppName" [preSelectGroups]="preSelectGroup"
|
||||
(selectGroup)="onSelectGroup($event)" (removeGroup)="onRemoveGroup($event)"></adf-cloud-group>
|
||||
<adf-cloud-group
|
||||
[mode]="groupMode"
|
||||
[validate]="groupPreselectValidation"
|
||||
[roles]="groupRoles"
|
||||
[appName]="groupAppName"
|
||||
[preSelectGroups]="preSelectGroup"
|
||||
(selectGroup)="onSelectGroup($event)"
|
||||
(removeGroup)="onRemoveGroup($event)"
|
||||
(warning)="onGroupsWarning($event)"></adf-cloud-group>
|
||||
</div>
|
||||
|
||||
<div class="app-group-list" *ngIf="canShowGroupList()">
|
||||
<h4>{{ 'PEOPLE_GROUPS_CLOUD.ALL_SELECTED_GROUPS' | translate }}</h4>
|
||||
<mat-list role="list">
|
||||
<mat-list-item *ngFor="let item of preSelectGroup" role="listitem">
|
||||
<mat-icon mat-list-icon>group</mat-icon>
|
||||
{{ item.name }}
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
<div *ngIf="invalidGroups.length > 0">
|
||||
<h4>{{ 'PEOPLE_GROUPS_CLOUD.INVALID_GROUPS' | translate }} <mat-icon>warning</mat-icon> </h4>
|
||||
<mat-list role="list">
|
||||
<mat-list-item *ngFor="let invalidGroup of invalidGroups" role="listitem">
|
||||
<mat-icon mat-list-icon>group</mat-icon>
|
||||
{{invalidGroup?.name}}
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
@@ -18,7 +18,7 @@
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { PeopleCloudComponent, GroupCloudComponent } from '@alfresco/adf-process-services-cloud';
|
||||
import { MatRadioChange, MatCheckboxChange } from '@angular/material';
|
||||
import { IdentityGroupModel } from '@alfresco/adf-core';
|
||||
import { IdentityGroupModel, IdentityUserModel } from '@alfresco/adf-core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-people-groups-cloud',
|
||||
@@ -33,14 +33,17 @@ export class PeopleGroupCloudDemoComponent {
|
||||
DEFAULT_PEOPLE_PLACEHOLDER: string = `[{"id": "1", email": "user@user.com", "firstName":"user", "lastName": "lastName", "username": "user"}]`;
|
||||
|
||||
peopleMode: string = PeopleCloudComponent.MODE_SINGLE;
|
||||
preSelectUsers: string[] = [];
|
||||
preSelectUsers: IdentityUserModel[] = [];
|
||||
invalidUsers: IdentityGroupModel[] = [];
|
||||
peopleRoles: string[] = [];
|
||||
peopleAppName: string;
|
||||
peopleFilterMode: string = this.DEFAULT_FILTER_MODE;
|
||||
peoplePreselectValidation: Boolean = false;
|
||||
groupPreselectValidation = false;
|
||||
|
||||
groupMode: string = GroupCloudComponent.MODE_SINGLE;
|
||||
preSelectGroup: IdentityGroupModel[] = [];
|
||||
invalidGroups: IdentityGroupModel[] = [];
|
||||
selectedGroupList: IdentityGroupModel[] = [];
|
||||
groupRoles: string[];
|
||||
groupAppName: string;
|
||||
@@ -117,6 +120,25 @@ export class PeopleGroupCloudDemoComponent {
|
||||
onChangePeopleValidation(event: MatCheckboxChange) {
|
||||
this.peoplePreselectValidation = event.checked;
|
||||
this.preSelectUsers = [...this.preSelectUsers];
|
||||
if (!this.peoplePreselectValidation) {
|
||||
this.invalidUsers = [];
|
||||
}
|
||||
}
|
||||
|
||||
onChangeGroupValidation(event: MatCheckboxChange) {
|
||||
this.groupPreselectValidation = event.checked;
|
||||
this.preSelectGroup = [...this.preSelectGroup];
|
||||
if (!this.groupPreselectValidation) {
|
||||
this.invalidGroups = [];
|
||||
}
|
||||
}
|
||||
|
||||
onGroupsWarning(warning: any) {
|
||||
this.invalidGroups = warning.groups;
|
||||
}
|
||||
|
||||
onUsersWarning(warning: any) {
|
||||
this.invalidUsers = warning.users;
|
||||
}
|
||||
|
||||
isStringArray(str: string) {
|
||||
@@ -149,6 +171,12 @@ export class PeopleGroupCloudDemoComponent {
|
||||
this.preSelectGroup = this.preSelectGroup.filter((value: any) => value.id !== group.id);
|
||||
}
|
||||
|
||||
onSelectUser(user: IdentityUserModel) {
|
||||
if (this.peopleMode === PeopleCloudComponent.MODE_MULTIPLE) {
|
||||
this.preSelectUsers.push(user);
|
||||
}
|
||||
}
|
||||
|
||||
onSelectGroup(group: IdentityGroupModel) {
|
||||
if (this.groupMode === GroupCloudComponent.MODE_MULTIPLE) {
|
||||
this.preSelectGroup.push(group);
|
||||
|
@@ -324,8 +324,8 @@ describe('GroupCloudComponent', () => {
|
||||
component.preSelectGroups = [];
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
const selectedUser = component.searchGroupsControl.value;
|
||||
expect(selectedUser).toBeNull();
|
||||
const selectedGroup = component.searchGroupsControl.value;
|
||||
expect(selectedGroup).toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -355,7 +355,7 @@ describe('GroupCloudComponent', () => {
|
||||
it('should pre-select all preSelectGroups when mode=multiple', (done) => {
|
||||
component.mode = 'multiple';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges({ 'preSelectUsers': change });
|
||||
component.ngOnChanges({ 'preSelectGroups': change });
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
@@ -407,7 +407,7 @@ describe('GroupCloudComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not filter groups if user does not have any specified role', (done) => {
|
||||
it('should not filter groups if group does not have any specified role', (done) => {
|
||||
fixture.detectChanges();
|
||||
checkGroupHasRoleSpy.and.returnValue(of(false));
|
||||
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
|
||||
@@ -498,4 +498,64 @@ describe('GroupCloudComponent', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiple Mode and Pre-selected groups with validate flag', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.mode = 'multiple';
|
||||
component.validate = true;
|
||||
component.preSelectGroups = <any> mockIdentityGroups;
|
||||
element = fixture.nativeElement;
|
||||
alfrescoApiService = TestBed.get(AlfrescoApiService);
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should emit warning if are invalid groups', (done) => {
|
||||
findGroupsByNameSpy.and.returnValue(Promise.resolve([]));
|
||||
const warnMessage = { message: 'INVALID_PRESELECTED_GROUPS', groups: [{ name: 'invalidGroupOne' }, { name: 'invalidGroupTwo' }] };
|
||||
component.validate = true;
|
||||
component.preSelectGroups = <any> [{ name: 'invalidGroupOne' }, { name: 'invalidGroupTwo' }];
|
||||
fixture.detectChanges();
|
||||
component.loadSinglePreselectGroup();
|
||||
component.warning.subscribe((response) => {
|
||||
expect(response).toEqual(warnMessage);
|
||||
expect(response.message).toEqual(warnMessage.message);
|
||||
expect(response.groups).toEqual(warnMessage.groups);
|
||||
expect(response.groups[0].name).toEqual('invalidGroupOne');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter group by name if validate true', (done) => {
|
||||
findGroupsByNameSpy.and.returnValue(of(mockIdentityGroups));
|
||||
component.mode = 'multiple';
|
||||
component.validate = true;
|
||||
component.preSelectGroups = <any> [{ name: mockIdentityGroups[1].name }, { name: mockIdentityGroups[2].name }];
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
component.filterPreselectGroups().then((result) => {
|
||||
expect(findGroupsByNameSpy).toHaveBeenCalled();
|
||||
expect(component.groupExists(result[0])).toEqual(true);
|
||||
expect(component.groupExists(result[1])).toEqual(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not preselect any group if name is invalid and validation enable', (done) => {
|
||||
findGroupsByNameSpy.and.returnValue(of([]));
|
||||
component.mode = 'single';
|
||||
component.validate = true;
|
||||
component.preSelectGroups = <any> [{ name: 'invalid group' }];
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
component.validatePreselectGroups().then((result) => {
|
||||
fixture.detectChanges();
|
||||
expect(findGroupsByNameSpy).toHaveBeenCalled();
|
||||
expect(result.length).toEqual(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -27,14 +27,15 @@ import {
|
||||
SimpleChanges,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
ChangeDetectionStrategy
|
||||
ChangeDetectionStrategy,
|
||||
SimpleChange
|
||||
} from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { trigger, state, style, transition, animate } from '@angular/animations';
|
||||
import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
|
||||
import { debounceTime } from 'rxjs/internal/operators/debounceTime';
|
||||
import { distinctUntilChanged, switchMap, mergeMap, filter, tap, map, takeUntil } from 'rxjs/operators';
|
||||
import { IdentityGroupModel, IdentityGroupSearchParam, IdentityGroupService } from '@alfresco/adf-core';
|
||||
import { IdentityGroupModel, IdentityGroupSearchParam, IdentityGroupService, LogService } from '@alfresco/adf-core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-cloud-group',
|
||||
@@ -57,7 +58,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
static MODE_SINGLE = 'single';
|
||||
static MODE_MULTIPLE = 'multiple';
|
||||
|
||||
/** Name of the application. If specified this shows the users who have access to the app. */
|
||||
/** Name of the application. If specified this shows the groups who have access to the app. */
|
||||
@Input()
|
||||
appName: string;
|
||||
|
||||
@@ -65,14 +66,21 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input()
|
||||
title: string;
|
||||
|
||||
/** User selection mode (single/multiple). */
|
||||
/** Group selection mode (single/multiple). */
|
||||
@Input()
|
||||
mode: string = GroupCloudComponent.MODE_SINGLE;
|
||||
|
||||
/** Array of users to be pre-selected. This pre-selects all users in multi selection mode and only the first user of the array in single selection mode. */
|
||||
/** Array of groups to be pre-selected. This pre-selects all groups in multi selection mode and only the first group of the array in single selection mode. */
|
||||
@Input()
|
||||
preSelectGroups: IdentityGroupModel[] = [];
|
||||
|
||||
/** This flag enables the validation on the preSelectGroups passed as input.
|
||||
* In case the flag is true the components call the identity service to verify the validity of the information passed as input.
|
||||
* Otherwise, no check will be done.
|
||||
*/
|
||||
@Input()
|
||||
validate: Boolean = false;
|
||||
|
||||
/** Show the info in readonly mode
|
||||
*/
|
||||
@Input()
|
||||
@@ -98,6 +106,10 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Output()
|
||||
changedGroups = new EventEmitter<IdentityGroupModel[]>();
|
||||
|
||||
/** Emitted when an warning occurs. */
|
||||
@Output()
|
||||
warning = new EventEmitter<any>();
|
||||
|
||||
@ViewChild('groupInput')
|
||||
private groupInput: ElementRef<HTMLInputElement>;
|
||||
|
||||
@@ -121,8 +133,12 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
currentTimeout: any;
|
||||
invalidGroups: IdentityGroupModel[] = [];
|
||||
|
||||
constructor(private identityGroupService: IdentityGroupService) { }
|
||||
constructor(
|
||||
private identityGroupService: IdentityGroupService,
|
||||
private logService: LogService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.initSearch();
|
||||
@@ -130,13 +146,15 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
|
||||
if (changes.preSelectGroups && this.hasPreSelectGroups()) {
|
||||
this.loadPreSelectGroups();
|
||||
} else {
|
||||
this.searchGroupsControl.setValue('');
|
||||
if (this.isPreselectedGroupsChanged(changes)) {
|
||||
if (this.isValidationEnabled()) {
|
||||
this.loadPreSelectGroups();
|
||||
} else {
|
||||
this.loadNoValidationPreselectGroups();
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.appName && this.isAppNameChanged(changes.appName)) {
|
||||
if (this.isAppNameChanged(changes.appName)) {
|
||||
this.disableSearch();
|
||||
this.loadClientId();
|
||||
} else {
|
||||
@@ -144,8 +162,14 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
private isAppNameChanged(change): boolean {
|
||||
return change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
|
||||
private isPreselectedGroupsChanged(changes: SimpleChanges): boolean {
|
||||
return changes.preSelectGroups
|
||||
&& changes.preSelectGroups.previousValue !== changes.preSelectGroups.currentValue
|
||||
&& this.hasPreSelectGroups();
|
||||
}
|
||||
|
||||
private isAppNameChanged(change: SimpleChange): boolean {
|
||||
return change && change.previousValue !== change.currentValue && this.appName && this.appName.length > 0;
|
||||
}
|
||||
|
||||
private async loadClientId() {
|
||||
@@ -220,20 +244,114 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
return false;
|
||||
}
|
||||
|
||||
private loadPreSelectGroups() {
|
||||
if (this.isMultipleMode()) {
|
||||
const groups = this.removeDuplicatedGroups([...this.preSelectGroups]);
|
||||
async searchGroup(groupName: any): Promise<IdentityGroupModel> {
|
||||
return (await this.identityGroupService.findGroupsByName(this.createSearchParam(groupName)).toPromise())[0];
|
||||
}
|
||||
|
||||
async filterPreselectGroups() {
|
||||
const promiseBatch = this.preSelectGroups.map(async (group: IdentityGroupModel) => {
|
||||
let result: any;
|
||||
try {
|
||||
result = await this.searchGroup(group.name);
|
||||
} catch (error) {
|
||||
result = [];
|
||||
this.logService.error(error);
|
||||
}
|
||||
const isGroupValid: boolean = this.groupExists(result);
|
||||
return isGroupValid ? result : null;
|
||||
});
|
||||
return Promise.all(promiseBatch);
|
||||
}
|
||||
|
||||
public groupExists(result: IdentityGroupModel): boolean {
|
||||
return result
|
||||
&& (result.id !== undefined
|
||||
|| result.name !== undefined);
|
||||
}
|
||||
|
||||
private isValidGroup(filteredGroups: IdentityGroupModel[], group: IdentityGroupModel): IdentityGroupModel {
|
||||
return filteredGroups.find((filteredGroup: IdentityGroupModel) => {
|
||||
return filteredGroup &&
|
||||
(filteredGroup.id === group.id ||
|
||||
filteredGroup.name === group.name);
|
||||
});
|
||||
}
|
||||
|
||||
async validatePreselectGroups(): Promise<IdentityGroupModel[]> {
|
||||
let filteredPreselectGroups: IdentityGroupModel[];
|
||||
let validGroups: IdentityGroupModel[] = [];
|
||||
|
||||
try {
|
||||
filteredPreselectGroups = await this.filterPreselectGroups();
|
||||
} catch (error) {
|
||||
validGroups = [];
|
||||
this.logService.error(error);
|
||||
}
|
||||
|
||||
await this.preSelectGroups.map((group: IdentityGroupModel) => {
|
||||
const validGroup = this.isValidGroup(filteredPreselectGroups, group);
|
||||
|
||||
if (validGroup) {
|
||||
validGroups.push(validGroup);
|
||||
} else {
|
||||
this.invalidGroups.push(group);
|
||||
}
|
||||
});
|
||||
validGroups = this.removeDuplicatedGroups(validGroups);
|
||||
return validGroups;
|
||||
}
|
||||
|
||||
public async loadSinglePreselectGroup() {
|
||||
const groups = await this.validatePreselectGroups();
|
||||
if (groups && groups.length > 0) {
|
||||
this.checkPreselectValidationErrors();
|
||||
this.searchGroupsControl.setValue(groups[0]);
|
||||
} else {
|
||||
this.checkPreselectValidationErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public async loadMultiplePreselectGroups() {
|
||||
const groups = await this.validatePreselectGroups();
|
||||
if (groups && groups.length > 0) {
|
||||
this.checkPreselectValidationErrors();
|
||||
this.selectedGroups = [...groups];
|
||||
this.selectedGroups$.next(this.selectedGroups);
|
||||
} else {
|
||||
this.checkPreselectValidationErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public checkPreselectValidationErrors() {
|
||||
if (this.invalidGroups.length > 0) {
|
||||
this.warning.emit({
|
||||
message: 'INVALID_PRESELECTED_GROUPS',
|
||||
groups: this.invalidGroups
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private loadPreSelectGroups() {
|
||||
if (!this.isMultipleMode()) {
|
||||
this.loadSinglePreselectGroup();
|
||||
} else {
|
||||
this.loadMultiplePreselectGroups();
|
||||
}
|
||||
}
|
||||
|
||||
loadNoValidationPreselectGroups() {
|
||||
this.selectedGroups = [...this.removeDuplicatedGroups([...this.preSelectGroups])];
|
||||
if (this.isMultipleMode()) {
|
||||
this.selectedGroups$.next(this.selectedGroups);
|
||||
} else {
|
||||
|
||||
if (this.currentTimeout) {
|
||||
clearTimeout(this.currentTimeout);
|
||||
}
|
||||
|
||||
this.currentTimeout = setTimeout(() => {
|
||||
this.searchGroupsControl.setValue(this.preSelectGroups[0]);
|
||||
this.onSelect(this.preSelectGroups[0]);
|
||||
this.searchGroupsControl.setValue(this.selectedGroups[0]);
|
||||
this.onSelect(this.selectedGroups[0]);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
@@ -290,7 +408,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
private removeDuplicatedGroups(groups: IdentityGroupModel[]): IdentityGroupModel[] {
|
||||
return groups.filter((group, index, self) =>
|
||||
index === self.findIndex((auxGroup) => {
|
||||
return group.id === auxGroup.id;
|
||||
return group.id === auxGroup.id && group.name === auxGroup.name;
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -333,6 +451,10 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.isFocused = isFocused;
|
||||
}
|
||||
|
||||
isValidationEnabled() {
|
||||
return this.validate === true;
|
||||
}
|
||||
|
||||
hasErrorMessage(): boolean {
|
||||
return !this.isFocused && this.hasError();
|
||||
}
|
||||
|
Reference in New Issue
Block a user