참고: 사용자 입력이나 편집 API를 통해 편집되지 않은 레코드에 대해서는 유효성 검사가 트리거되지 않습니다. 셀의 시각적 표시기는 사용자 상호 작용이나 유효성 검사 서비스의 markAsTouched API를 통해 관련 입력이 터치된 것으로 간주되는 경우에만 표시됩니다.
Angular Tree Grid Validation Customization Options
셀이 잘못된 상태에 들어갈 때 오류 도구 설명에 표시될 고유한 사용자 정의 오류 템플릿을 정의할 수 있습니다. 이는 사용자 정의 오류 메시지를 추가하거나 메시지의 모양이나 내용을 변경하려는 시나리오에서 유용합니다.
<igx-column... ><ng-templateigxCellValidationErrorlet-cell='cell'let-defaultErr="defaultErrorTemplate"><ng-container *ngTemplateOutlet="defaultErr"></ng-container><div *ngIf="cell.validation.errors?.['phoneFormat']">
Please enter correct phone format
</div></ng-template></igx-column>html
Prevent exiting edit mode on invalid state
어떤 경우에는 데이터에 유효하지 않은 값을 제출하는 것을 허용하지 않을 수도 있습니다. 해당 시나리오에서는 cellEdit 또는 rowEdit 이벤트를 사용하고 새 값이 유효하지 않은 경우 이벤트를 취소할 수 있습니다. 두 이벤트의 인수 모두 valid 속성을 가지며 이에 따라 취소될 수 있습니다. 사용 방법은 Cross-field Validation 예제에서 확인할 수 있습니다.
오류 메시지는 각 셀에 대한 오류를 수집하는 stateMessage 함수에서 수집됩니다. 왜냐하면 각 열에는 템플릿 양식 유효성 검사가 있을 수 있고 사용자 정의 rowValidator에서 오는 행 자체에 대한 오류를 확인할 수 있기 때문입니다.
publicstateMessage(cell: CellType) {
const messages = [];
const row = cell.row;
const cellValidationErrors = row.cells.filter(x => !!x.validation.errors);
cellValidationErrors.forEach(cell => {
if (cell.validation.errors) {
if (cell.validation.errors.required) {
messages.push(`The \`${cell.column.header}\` column is required.`);
}
// Other cell errors...
}
});
if (row.validation.errors?.ageLessHireDate) {
messages.push(`\`Age\` cannot be less than 18 when the person was hired.`);
}
if (row.validation.errors?.invalidAddress) {
messages.push(`Selected \`City\` does not match the \`Country\`.`);
}
if (messages.length === 0 && this.isRowValid(cell)) {
messages.push('OK');
}
return messages;
}
typescript
Cross-field example
아래 샘플은 실제 크로스 필드 유효성 검사를 보여줍니다.
EXAMPLE
TS
HTML
SCSS
/* eslint-disable @typescript-eslint/naming-convention */import { Component, OnInit, ViewChild } from'@angular/core';
import { FormGroup, ValidationErrors, ValidatorFn, FormsModule, ReactiveFormsModule } from'@angular/forms';
import { ColumnPinningPosition, CellType, IGridEditEventArgs, IgxTreeGridComponent, IPinningConfig, IgxSwitchComponent, IgxColumnComponent, IgxColumnRequiredValidatorDirective, IgxColumnMinValidatorDirective, IgxColumnMaxValidatorDirective, IgxCellEditorTemplateDirective, IgxSelectComponent, IgxFocusDirective, IgxSelectItemComponent, IgxCellTemplateDirective, IgxTooltipTargetDirective, IgxTooltipDirective, IgxButtonDirective } from'igniteui-angular';
import { IGridFormGroupCreatedEventArgs } from'igniteui-angular/lib/grids/common/grid.interface';
import { generateEmployeeDetailedFlatData } from'../data/employees-flat-detailed';
import { IgxPreventDocumentScrollDirective } from'../../directives/prevent-scroll.directive';
@Component({
selector: 'app-tree-grid-validator-service-cross-field-component',
styleUrls: ['tree-grid-validator-service-cross-field.component.scss'],
templateUrl: 'tree-grid-validator-service-cross-field.component.html',
imports: [IgxSwitchComponent, FormsModule, IgxTreeGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxColumnRequiredValidatorDirective, IgxColumnMinValidatorDirective, IgxColumnMaxValidatorDirective, IgxCellEditorTemplateDirective, IgxSelectComponent, ReactiveFormsModule, IgxFocusDirective, IgxSelectItemComponent, IgxCellTemplateDirective, IgxTooltipTargetDirective, IgxTooltipDirective, IgxButtonDirective]
})
exportclassTreeGridValidatorServiceCrossFieldComponentimplementsOnInit{
@ViewChild('treeGrid', { static: true })
public treeGrid: IgxTreeGridComponent;
public rowEdit: boolean = false;
public pinningConfig: IPinningConfig = { columns: ColumnPinningPosition.End };
public data: any[];
public countryData: Map<string, object>;
public countries = [];
public cities = [];
public ngOnInit(): void {
this.data = generateEmployeeDetailedFlatData();
this.countryData = newMap(this.data.map(i => [i.Country, {}]));
this.data.forEach(rec => {
const country = rec.Country;
const city = rec.City;
this.countryData.get(country)[city] = city;
});
this.countries = [...new Set(this.data.map(x => x.Country))];
this.cities = [...new Set(this.data.map(x => x.City))];
}
publiceditHandler(event: IGridEditEventArgs) {
if (!event.valid) {
event.cancel = true;
}
}
publicformCreateHandler(evt: IGridFormGroupCreatedEventArgs) {
evt.formGroup.addValidators(this.rowValidator());
}
private rowValidator(): ValidatorFn {
return (formGroup: FormGroup): ValidationErrors | null => {
let returnObject = {};
const age = formGroup.get('Age');
const hireDate = formGroup.get('HireDate');
if((newDate().getFullYear() - newDate(hireDate.value).getFullYear()) + 18 >= age.value) {
returnObject['ageLessHireDate'] = true;
}
const city = formGroup.get('City');
const country = formGroup.get('Country');
const validCities = this.countryData.get(country.value);
if (!validCities || !validCities[city.value]) {
returnObject['invalidAddress'] = true;
}
return returnObject;
};
}
publicisRowValid(cell: CellType) {
return !cell.row.validation.errors && !cell.row.cells.some(c => !!c.validation.errors);
}
publicstateMessage(cell: CellType) {
const messages = [];
const cellValidationErrors = cell.row.cells.filter(x => !!x.validation.errors);
cellValidationErrors.forEach(cell => {
const cellErrors = cell.validation.errors;
if (cellErrors?.required) {
messages.push(`The \`${cell.column.header}\` column is required.`);
}
if (cellErrors?.min) {
messages.push(`A value of at least ${cellErrors.min.min} should be entered for \`${cell.column.header}\` column.`);
}
if (cellErrors?.max) {
messages.push(`A value of at maximum ${cellErrors.max.max} should be entered for \`${cell.column.header}\` column.`);
}
});
const rowErrors = cell.row.validation.errors;
if (rowErrors?.ageLessHireDate) {
messages.push(`\`Age\` cannot be less than 18 when the person was hired.`);
}
if (rowErrors?.invalidAddress) {
messages.push(`Selected \`City\` does not match the \`Country\`.`);
}
if (messages.length === 0 && this.isRowValid(cell)) {
messages.push('OK');
}
return messages;
}
publiccommit() {
const invalidTransactions = this.treeGrid.validation.getInvalid();
if (invalidTransactions.length > 0 && !confirm('You\'re committing invalid transactions. Are you sure?')) {
return;
}
this.treeGrid.transactions.commit(this.data);
this.treeGrid.validation.clear();
}
}
ts
아래 예에서는 도구 설명에 표시되는 유효성 검사 메시지에 대해 노출된 템플릿을 사용하고 오류 색상을 재정의하여 유효성 검사의 기본 모양을 수정합니다. 또한 유효하지 않은 행의 배경 스타일을 지정하여 더욱 뚜렷하게 만듭니다.
Import theme
css 변수에 스타일을 지정하고 액세스하는 가장 쉬운 방법은 app의 글로벌 스타일 파일(일반적으로 styles.scss)에 스타일을 정의하는 것입니다. 가장 먼저 해야 할 일은 themes/index 파일을 가져오는 것입니다. 이렇게 하면 Ignite UI for Angular Sass 프레임워크의 모든 강력한 도구에 액세스할 수 있습니다.
@use"igniteui-angular/theming" as *;
// IMPORTANT: Prior to Ignite UI for Angular version 13 use:// @import '~igniteui-angular/lib/core/styles/themes/index';scss