Skip to content

Commit b87cc15

Browse files
3phasetishko0skrustevdkamburovmddragnev
authored
Extended Validator Service Sample (#3073)
* Adds extended sample declarations * Commiting grid with sophisticated transactions * Adding custom validation for dates * Adds backbone of the extended component * Gets rid of unneeded imports in config generator & simplifies * Hierarchical grid sample * Adds sample for tree grid * Modifies hgrid sample data * Updates config generators * Adds missing method to hgrid & tree grid * test(grids): updated samples * test(grids): updated samples for ext validation * tests(grids): updated samples as per review * tests(grids): updated commit method in samples * tests(grids): updated default templates * test(grids): fixed commit and hgrid transactions * Remove duplicate record in hierarchical data. Cleanup the samples a bit. * Simplify grid extended validator sample styles. * updated package.json to include validator * added .lock file as well * updated fromgroupArgs * filtered data out of unique rows * updated grids samples with new api * Clear child grid validation errors on commit. Check if child grids has any errors on commit. Co-authored-by: tishko <ttonev@infragistics.com> Co-authored-by: skrustev <striker18@mail.bg> Co-authored-by: Deyan Kamburov <dkamburov@users.noreply.github.com> Co-authored-by: Martin Dragnev <mddragnev@gmail.com>
1 parent 786073f commit b87cc15

24 files changed

Lines changed: 631 additions & 80 deletions

live-editing/configs/GridConfigGenerator.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,20 @@ export class GridConfigGenerator implements IConfigGenerator {
13961396
})
13971397
}));
13981398

1399+
configs.push(new Config({
1400+
component: 'GridValidatorServiceExtendedComponent',
1401+
additionalFiles: [
1402+
'/src/app/directives/prevent-scroll.directive.ts',
1403+
'/src/app/data/employeesData.ts'
1404+
1405+
],
1406+
appModuleConfig: new AppModuleConfig({
1407+
imports: ['GridValidatorServiceExtendedComponent', 'IgxGridModule', 'IgxFocusModule', 'IgxPreventDocumentScrollModule'],
1408+
ngDeclarations: ['GridValidatorServiceExtendedComponent', 'ForbiddenValidatorDirective'],
1409+
ngImports: ['IgxPreventDocumentScrollModule', 'IgxGridModule', 'IgxFocusModule']
1410+
})
1411+
}));
1412+
13991413
return configs;
14001414
}
14011415
}

live-editing/configs/HierarchicalGridConfigGenerator.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,20 @@ export class HierarchicalGridConfigGenerator implements IConfigGenerator {
984984
component: 'HGridValidationStyleComponent'
985985
}));
986986

987+
configs.push(new Config({
988+
component: 'HierarchicalGridValidatorServiceExtendedComponent',
989+
additionalFiles: [
990+
'/src/app/directives/prevent-scroll.directive.ts',
991+
'/src/app/data/hierarchical-data.ts'
992+
993+
],
994+
appModuleConfig: new AppModuleConfig({
995+
imports: ['HierarchicalGridValidatorServiceExtendedComponent', 'IgxHierarchicalGridModule', 'IgxPreventDocumentScrollModule'],
996+
ngDeclarations: ['HierarchicalGridValidatorServiceExtendedComponent', 'ForbiddenValidatorDirective'],
997+
ngImports: ['IgxPreventDocumentScrollModule', 'IgxHierarchicalGridModule']
998+
})
999+
}));
1000+
9871001
return configs;
9881002
}
9891003
}

live-editing/configs/TreeGridConfigGenerator.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,20 @@ export class TreeGridConfigGenerator implements IConfigGenerator {
11861186
shortenComponentPathBy: '/tree-grid/'
11871187
}));
11881188

1189+
configs.push(new Config({
1190+
component: 'TreeGridValidatorServiceExtendedComponent',
1191+
additionalFiles: ['/src/app/directives/prevent-scroll.directive.ts',
1192+
'/src/app/data/utils.ts',
1193+
'/src/app/tree-grid/data/employees-flat.ts'
1194+
],
1195+
appModuleConfig: new AppModuleConfig({
1196+
imports: ['IgxPreventDocumentScrollModule', 'IgxTreeGridModule', 'TreeGridValidatorServiceExtendedComponent',
1197+
'IgxButtonModule'],
1198+
ngDeclarations: ['TreeGridValidatorServiceExtendedComponent', 'ForbiddenValidatorDirective'],
1199+
ngImports: ['IgxPreventDocumentScrollModule', 'IgxTreeGridModule', 'IgxButtonModule']
1200+
})
1201+
}));
1202+
11891203
return configs;
11901204
}
11911205
}

src/app/data/hierarchical-data.ts

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -573,49 +573,6 @@ export const CUSTOMERS = [{
573573
Discount: 0.0000000e+000
574574
}]
575575
}]
576-
}, {
577-
CustomerID: "HANAR",
578-
CompanyName: "Hanari Carnes",
579-
ContactName: "Mario Pontes",
580-
ContactTitle: "Accounting Manager",
581-
Address: "Rua do Paço, 67",
582-
City: "Rio de Janeiro",
583-
Region: "RJ",
584-
PostalCode: "05454-876",
585-
Country: "Brazil",
586-
Phone: "(21) 555-0091",
587-
Fax: "(21) 555-8765",
588-
Orders: [{
589-
OrderID: 10253,
590-
EmployeeID: 3,
591-
OrderDate: new Date("1996-07-10T00:00:00"),
592-
RequiredDate: new Date("1996-07-24T00:00:00"),
593-
ShippedDate: new Date("1996-07-16T00:00:00"),
594-
ShipVia: 2,
595-
Freight: 58.1700,
596-
ShipName: "Hanari Carnes",
597-
ShipAddress: "Rua do Paço, 67",
598-
ShipCity: "Rio de Janeiro",
599-
ShipRegion: "RJ",
600-
ShipPostalCode: "05454-876",
601-
ShipCountry: "Brazil",
602-
OrderDetails: [{
603-
ProductID: 31,
604-
UnitPrice: 10.0000,
605-
Quantity: 20,
606-
Discount: 0.0000000e+000
607-
}, {
608-
ProductID: 39,
609-
UnitPrice: 14.4000,
610-
Quantity: 42,
611-
Discount: 0.0000000e+000
612-
}, {
613-
ProductID: 49,
614-
UnitPrice: 16.0000,
615-
Quantity: 40,
616-
Discount: 0.0000000e+000
617-
}]
618-
}]
619576
}, {
620577
CustomerID: "CHOPS",
621578
CompanyName: "Chop-suey Chinese",
@@ -32882,4 +32839,4 @@ export const CUSTOMERS = [{
3288232839
}]
3288332840
}]
3288432841
}
32885-
];
32842+
];

src/app/grid/grid-routes-data.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,6 @@ export const gridsRoutesData = {
121121
'grid-with-rating': { displayName: 'Grid with Rating', parentName: 'Rating' },
122122
'grid-validator-service': { displayName: 'Grid Validator Service', parentName: 'Grid' },
123123
'grid-cross-field-validator-service': { displayName: 'Grid Cross Field Validator Service ', parentName: 'Grid' },
124-
'grid-validation-style': { displayName: 'Grid with Validation Styles', parentName: 'Grid' }
124+
'grid-validation-style': { displayName: 'Grid with Validation Styles', parentName: 'Grid' },
125+
'grid-validator-service-extended': { displayName: 'Grid Validator Service Extended', parentName: 'Grid'}
125126
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<div class="grid-wrapper">
2+
<igx-grid #grid1 [data]="data" [width]="'100%'" [height]="'480px'" [autoGenerate]="false" [batchEditing]="true"
3+
[primaryKey]="'id'" (formGroupCreated)='formCreateHandler($event)'>
4+
<igx-column field="Avatar" header="Photo" dataType="string" width="80" [editable]="false">
5+
<ng-template igxCell let-cell="cell">
6+
<div class="cell__inner avatar-cell">
7+
<igx-avatar [src]="cell.row.data.avatar" [roundShape]="true" size="small"></igx-avatar>
8+
</div>
9+
</ng-template>
10+
</igx-column>
11+
<igx-column field="name" header="Name" [editable]="true" required></igx-column>
12+
<igx-column field="company" header="Company" [editable]="true"></igx-column>
13+
<igx-column field="email" width="190" header="Email" [editable]="true" required email></igx-column>
14+
<igx-column field="fax" header="Phone" [editable]="true" phoneFormat="\+\d{1}\-(?!0)(\d{3})\-(\d{3})\-(\d{4})\b">
15+
<ng-template igxCellValidationError let-cell='cell' let-defaultErr="defaultErrorTemplate">
16+
<ng-container *ngTemplateOutlet="defaultErr" >
17+
</ng-container>
18+
<div *ngIf="cell.validation.errors?.['phoneFormat']">
19+
Please enter correct phone format
20+
</div>
21+
</ng-template>
22+
</igx-column>
23+
<igx-column field="created_on" header="Date of Registration" width="170" [editable]="true" [dataType]="'date'" required>
24+
<ng-template igxCellValidationError let-cell='cell' let-defaultErr='defaultErrorTemplate'>
25+
<ng-container *ngTemplateOutlet="defaultErr" >
26+
</ng-container>
27+
<div *ngIf="cell.validation.errors?.['futureDate']">
28+
The date cannot be in the future.
29+
</div>
30+
</ng-template>
31+
<ng-template igxCell let-cell>
32+
{{ cell | date: 'longDate' }}
33+
</ng-template>
34+
</igx-column>
35+
<igx-column field="last_activity" header="Last Active" width="170" [editable]="true" [dataType]="'date'" required>
36+
<ng-template igxCell let-cell>
37+
{{ cell | date: 'longDate' }}
38+
</ng-template>
39+
<ng-template igxCellValidationError let-cell='cell' let-defaultErr="defaultErrorTemplate">
40+
<ng-container *ngTemplateOutlet="defaultErr">
41+
</ng-container>
42+
<div *ngIf="cell.validation.errors?.['futureDate']">
43+
The date cannot be in the future.
44+
</div>
45+
<div *ngIf="cell.validation.errors?.['pastDate']">
46+
The date cannot be before the 5th of November 2010
47+
</div>
48+
</ng-template>
49+
</igx-column>
50+
<igx-column field="estimated_sales" header="Estimated Sales" [editable]="true" [dataType]="'number'" required min="0">
51+
</igx-column>
52+
<igx-column field="deals_lost" header="Deals Lost" [editable]="true" [dataType]="'number'" required min="0">
53+
</igx-column>
54+
<igx-column field="deals_won" header="Deals Won" [editable]="true" [dataType]="'number'" required min="0">
55+
</igx-column>
56+
<igx-column field="deals_pending" header="Deals Pending" [editable]="true" [dataType]="'number'" required min="0">
57+
</igx-column>
58+
</igx-grid>
59+
</div>
60+
61+
<div class="buttons-wrapper">
62+
<button igxButton [disabled]="!grid1.transactions.canUndo" (click)="undo()">Undo</button>
63+
<button igxButton [disabled]="!grid1.transactions.canRedo" (click)="redo()">Redo</button>
64+
<button igxButton [disabled]="grid1.transactions.getAggregatedChanges(false).length < 1" (click)="commit()">Commit</button>
65+
</div>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.grid-wrapper {
2+
margin: 0 auto;
3+
padding: 16px;
4+
}
5+
6+
.buttons-wrapper {
7+
display: flex;
8+
flex-direction: row;
9+
justify-content: left;
10+
padding: 10px 0;
11+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { Component, Directive, Input, ViewChild } from '@angular/core';
2+
import { AbstractControl, FormGroup, NG_VALIDATORS, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
3+
import { IgxGridComponent } from 'igniteui-angular';
4+
import { IGridFormGroupCreatedEventArgs } from 'igniteui-angular/lib/grids/common/grid.interface';
5+
import { employeesData } from '../../data/employeesData';
6+
7+
export function phoneFormatValidator(phoneReg: RegExp): ValidatorFn {
8+
return (control: AbstractControl): ValidationErrors | null => {
9+
const match = phoneReg.test(control.value);
10+
return match ? null : { phoneFormat: { value: control.value } } ;
11+
}
12+
}
13+
14+
@Directive({
15+
selector: '[phoneFormat]',
16+
providers: [{ provide: NG_VALIDATORS, useExisting: PhoneFormatDirective, multi: true }]
17+
})
18+
export class PhoneFormatDirective extends Validators {
19+
@Input('phoneFormat')
20+
public phoneFormatString = '';
21+
22+
public validate(control: AbstractControl): ValidationErrors | null {
23+
return this.phoneFormatString ? phoneFormatValidator(new RegExp(this.phoneFormatString, 'i'))(control)
24+
: null;
25+
}
26+
}
27+
28+
@Component({
29+
selector: 'app-grid-validator-service-extended',
30+
styleUrls: ['./grid-validator-service-extended.component.scss'],
31+
templateUrl: './grid-validator-service-extended.component.html'
32+
})
33+
export class GridValidatorServiceExtendedComponent {
34+
35+
@ViewChild('grid1', { read: IgxGridComponent })
36+
public grid: IgxGridComponent;
37+
38+
public data = employeesData;
39+
40+
public formCreateHandler(formGroupArgs: IGridFormGroupCreatedEventArgs) {
41+
const createdOnRecord = formGroupArgs.formGroup.get('created_on');
42+
const lastActiveRecord = formGroupArgs.formGroup.get('last_activity');
43+
createdOnRecord.addValidators(this.futureDateValidator());
44+
lastActiveRecord.addValidators([this.pastDateValidator(), this.futureDateValidator()]);
45+
}
46+
47+
public commit() {
48+
const invalidTransactions = this.grid.validation.getInvalid();
49+
if (invalidTransactions.length > 0 && !confirm('You\'re committing invalid transactions. Are you sure?')) {
50+
return;
51+
}
52+
53+
this.grid.transactions.commit(this.data);
54+
this.grid.validation.clear();
55+
}
56+
57+
public undo() {
58+
/* exit edit mode and commit changes */
59+
this.grid.endEdit(true);
60+
this.grid.transactions.undo();
61+
}
62+
63+
public redo() {
64+
/* exit edit mode and commit changes */
65+
this.grid.endEdit(true);
66+
this.grid.transactions.redo();
67+
}
68+
69+
public futureDateValidator(): ValidatorFn {
70+
return (control: AbstractControl): ValidationErrors | null => {
71+
const date = control.value;
72+
if(date > new Date()){
73+
return { futureDate: { value: control.value } };
74+
}
75+
return null;
76+
}
77+
}
78+
79+
public pastDateValidator(): ValidatorFn {
80+
return (control: AbstractControl): ValidationErrors | null => {
81+
const date = control.value;
82+
let pastDate = new Date('Nov 5 2010');
83+
if(pastDate){
84+
return pastDate < date ? null : { pastDate: { value: control.value } }
85+
} else return null;
86+
}
87+
}
88+
}

src/app/grid/grids-routing.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ import { GridWithRatingComponent } from './grid-with-rating/grid-with-rating.com
127127
import { GridValidatorServiceComponent } from './grid-validator-service/grid-validator-service.component';
128128
import { GridValidatorServiceCrossFieldComponent } from './grid-validator-service-cross-field/grid-validator-service-cross-field.component';
129129
import { GridValidationStyleComponent } from './grid-validation-style/grid-validation-style.component';
130+
import { GridValidatorServiceExtendedComponent } from './grid-validator-service-extended/grid-validator-service-extended.component';
130131
// tslint:enable:max-line-length
131132

132133
export const gridsRoutes: Routes = [
@@ -734,6 +735,11 @@ export const gridsRoutes: Routes = [
734735
component: GridValidationStyleComponent,
735736
data: gridsRoutesData['grid-validation-style'],
736737
path: 'grid-validation-style'
738+
},
739+
{
740+
component: GridValidatorServiceExtendedComponent,
741+
data: gridsRoutesData['grid-validator-service-extended'],
742+
path: 'grid-validator-service-extended'
737743
}
738744
];
739745

src/app/grid/grids.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ import { GridWithRatingComponent } from './grid-with-rating/grid-with-rating.com
136136
import { GridValidatorServiceComponent } from './grid-validator-service/grid-validator-service.component';
137137
import { GridValidatorServiceCrossFieldComponent } from './grid-validator-service-cross-field/grid-validator-service-cross-field.component';
138138
import { GridValidationStyleComponent } from './grid-validation-style/grid-validation-style.component';
139+
import { GridValidatorServiceExtendedComponent, PhoneFormatDirective } from './grid-validator-service-extended/grid-validator-service-extended.component';
139140

140141
@NgModule({
141142
declarations: [
@@ -261,7 +262,9 @@ import { GridValidationStyleComponent } from './grid-validation-style/grid-valid
261262
GridWithRatingComponent,
262263
GridValidatorServiceComponent,
263264
GridValidatorServiceCrossFieldComponent,
264-
GridValidationStyleComponent
265+
GridValidationStyleComponent,
266+
GridValidatorServiceExtendedComponent,
267+
PhoneFormatDirective
265268
],
266269
imports: [
267270
CommonModule,

0 commit comments

Comments
 (0)