validation
This commit is contained in:
		
							parent
							
								
									7ffcc93769
								
							
						
					
					
						commit
						1cd6e16ce4
					
				| @ -4,11 +4,13 @@ import { ModalModule } from 'ngx-bootstrap/modal'; | ||||
| import { CommandModalDirective } from './directives/command-modal.directive'; | ||||
| import { CommandModalComponent } from './command-modal/command-modal.component'; | ||||
| import { InputValidatorDirective } from './directives/input-validator.directive'; | ||||
| import { FormsModule } from '@angular/forms'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|   imports: [ | ||||
|     CommonModule, | ||||
|     ModalModule.forRoot() | ||||
|     ModalModule.forRoot(), | ||||
|     FormsModule | ||||
|   ], | ||||
|   declarations: [CommandModalDirective, CommandModalComponent, InputValidatorDirective], | ||||
|   exports: [CommandModalDirective] | ||||
|  | ||||
| @ -7,13 +7,12 @@ | ||||
| <div class="modal-body"> | ||||
|     <ng-container [ngTemplateOutlet]="template" | ||||
|         [ngTemplateOutletContext]="{ $implicit: commandModel, loading: loading }"></ng-container> | ||||
|     <div *ngIf="validationMessage" class="alert alert-danger mt-2" style="white-space: pre-wrap">{{validationMessage}}</div> | ||||
| </div> | ||||
| <div class="modal-footer"> | ||||
|     <button type="button" class="btn btn-light" (click)="modalRef.hide()" | ||||
|         [attr.disabled]="loading">{{ cancelText }}</button> | ||||
|     <button type="button" class="btn btn-primary" (click)="attemptSave()" | ||||
|         [attr.disabled]="loading">{{ commandText }}</button> | ||||
| 
 | ||||
|         [disabled]="loading">{{ cancelText }}</button> | ||||
|     <button type="button" class="btn btn-primary" [disabled]="loading" (click)="onSubmit()">{{ commandText }}</button> | ||||
|     <br> | ||||
| 
 | ||||
|     <div class="progress" style="width: 100%" *ngIf="loading"> | ||||
| @ -21,4 +20,5 @@ | ||||
|             aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div> | ||||
|     </div> | ||||
| 
 | ||||
| </div> | ||||
| </div> | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,3 @@ | ||||
| .field-error{ | ||||
|     border: 1px solid red; | ||||
| } | ||||
| @ -3,6 +3,7 @@ import { IDataSource } from '@poweredsoft/data'; | ||||
| import { BsModalRef } from 'ngx-bootstrap/modal'; | ||||
| import { finalize} from 'rxjs/operators'; | ||||
| import { Subscription } from 'rxjs'; | ||||
| import { NgForm } from '@angular/forms'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'psbx-command-modal', | ||||
| @ -20,6 +21,8 @@ export class CommandModalComponent implements OnInit, OnDestroy { | ||||
|   loading: boolean; | ||||
|   commandText: string; | ||||
|   cancelText: string; | ||||
|   form:NgForm; | ||||
|   validationMessage:string ; | ||||
| 
 | ||||
|   private _notifyMessage: Subscription; | ||||
|   private _validationError: Subscription; | ||||
| @ -33,16 +36,26 @@ export class CommandModalComponent implements OnInit, OnDestroy { | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this._notifyMessage = this.dataSource.notifyMessage$.subscribe(message => { | ||||
|        | ||||
|       if (message.type != 'info') | ||||
|         this.validationMessage = message.message; | ||||
|     }); | ||||
| 
 | ||||
|     this._validationError = this.dataSource.validationError$.subscribe(validatorErrors => { | ||||
|       console.log(validatorErrors); | ||||
|     this._validationError = this.dataSource.validationError$.subscribe(validatorErrors => {       | ||||
|       let validationSummary = ''; | ||||
|       Object.getOwnPropertyNames(validatorErrors.errors).forEach(property => { | ||||
|         const errors = validatorErrors.errors[property].join('\n'); | ||||
|         validationSummary += errors + '\n'; | ||||
|       }); | ||||
|       this.validationMessage = validationSummary.trim(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   attemptSave() { | ||||
|   onSubmit(){ | ||||
|      | ||||
| 
 | ||||
|     this.loading = true; | ||||
|     this.validationMessage = null; | ||||
| 
 | ||||
|     this.dataSource.executeCommandByName(this.command, this.commandModel) | ||||
|       .pipe( | ||||
|         finalize(() => { | ||||
| @ -59,4 +72,8 @@ export class CommandModalComponent implements OnInit, OnDestroy { | ||||
|       }); | ||||
|   } | ||||
| 
 | ||||
|   attemptSave() { | ||||
|      | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -11,17 +11,15 @@ | ||||
|         <ng-container [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{ $implicit: modelForm, loading: loading }"> | ||||
|         </ng-container> | ||||
| 
 | ||||
|         <div *ngIf="errorMessage" class="alert alert-danger mt-2"> | ||||
|             {{ errorMessage }} | ||||
|         </div> | ||||
|         <div *ngIf="errorMessage" class="alert alert-danger mt-2" style="white-space: pre-wrap">{{ errorMessage }}</div> | ||||
|     </div> | ||||
|    | ||||
|      | ||||
|      | ||||
|     <div class="modal-footer"> | ||||
|         <button type="button" class="btn btn-light" (click)="modalRef.hide()" | ||||
|             [attr.disabled]="loading">{{ cancelText }}</button> | ||||
|         <button type="button" class="btn btn-primary" (click)="attemptSave()" [attr.disabled]="loading">{{commandText}}</button> | ||||
|             [disabled]="loading">{{ cancelText }}</button> | ||||
|         <button type="button" class="btn btn-primary" (click)="attemptSave()" [disabled]="loading">{{commandText}}</button> | ||||
|         <br> | ||||
|      | ||||
|         <div class="progress" style="width: 100%" *ngIf="loading"> | ||||
|  | ||||
| @ -23,17 +23,16 @@ export class FormGroupCommandModalComponent implements OnInit { | ||||
|   commandText: string; | ||||
|   cancelText: string; | ||||
|   errorMessage: string; | ||||
|   commandModel:any; | ||||
|   commandModel:any;  | ||||
|    | ||||
|   private _notifyMessage: Subscription; | ||||
|   private _validationError: Subscription; | ||||
| 
 | ||||
|   constructor(public modalRef: BsModalRef) { } | ||||
| 
 | ||||
|   ngOnDestroy(): void { | ||||
|     /* | ||||
|     this._notifyMessage.unsubscribe(); | ||||
|     this._validationError.unsubscribe(); | ||||
|     */ | ||||
|   } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
| @ -41,19 +40,24 @@ export class FormGroupCommandModalComponent implements OnInit { | ||||
|     // this._notifyMessage = this.dataSource.notifyMessage$.subscribe(message => {
 | ||||
|        | ||||
|     // });
 | ||||
| 
 | ||||
|     // this._validationError = this.dataSource.validationError$.subscribe(validatorErrors => {
 | ||||
|     //   console.log(validatorErrors);
 | ||||
|     // });
 | ||||
|     | ||||
|     this._validationError = this.dataSource.validationError$.subscribe(validatorErrors => {       | ||||
|       let validationSummary = ''; | ||||
|       Object.getOwnPropertyNames(validatorErrors.errors).forEach(property => { | ||||
|         const errors = validatorErrors.errors[property].join('\n'); | ||||
|         validationSummary += errors + '\n'; | ||||
|       }); | ||||
|       this.errorMessage = validationSummary.trim(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   attemptSave() { | ||||
|     this.errorMessage = null; | ||||
|     if (!this.modelForm.valid) | ||||
|     { | ||||
|       this.errorMessage = 'Form is not valid, please enter all required fields'; | ||||
|       return; | ||||
|     } | ||||
|     // this.errorMessage = null;
 | ||||
|     // if (!this.modelForm.valid)
 | ||||
|     // {
 | ||||
|     //   this.errorMessage = 'Form is not valid, please enter all required fields';      
 | ||||
|     //   return;
 | ||||
|     // }
 | ||||
| 
 | ||||
|     const finalModel = this.modelForm.value;   | ||||
|     if(this.commandModel.id) | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| <div class="spinner-border" role="status"> | ||||
|     <span class="sr-only">Loading...</span> | ||||
| <div class="center"> | ||||
|     <div class="spinner-grow text-primary" role="status"> | ||||
|     </div> | ||||
|     <div class="spinner-grow text-secondary" role="status"> | ||||
|     </div> | ||||
|     <div class="spinner-grow text-primary" role="status"> | ||||
|     </div> | ||||
|     <div class="spinner-grow text-secondary" role="status"> | ||||
|     </div> | ||||
| </div> | ||||
| @ -0,0 +1,6 @@ | ||||
| .center { | ||||
|     position: absolute; | ||||
|     top: 50%; | ||||
|     left: 50%; | ||||
|     transform: translate(-50%, -50%); | ||||
|   } | ||||
| @ -13,12 +13,18 @@ import { DataGridLoaderDirective } from './directives/data-grid-loader.directive | ||||
| 
 | ||||
| 
 | ||||
| @NgModule({ | ||||
|   declarations: [DataGridComponent,DataGridColDirective,DataGridColHeaderDirective,DataGridCellDirective, DataGridFooterDirective, DataGridHeaderDirective, DataGridLoaderDirective, | ||||
|   declarations: [ | ||||
|     DataGridComponent,DataGridColDirective,DataGridColHeaderDirective, | ||||
|     DataGridCellDirective, DataGridFooterDirective, DataGridHeaderDirective,  | ||||
|     DataGridLoaderDirective, | ||||
|      | ||||
|   ], | ||||
|   imports: [ | ||||
|     CommonModule | ||||
|   ], | ||||
|   exports: [DataGridComponent,DataGridColDirective,DataGridColHeaderDirective,DataGridCellDirective,DataGridFooterDirective, DataGridHeaderDirective,DataGridLoaderDirective] | ||||
|   exports: [ | ||||
|     DataGridComponent,DataGridColDirective,DataGridColHeaderDirective, | ||||
|     DataGridCellDirective,DataGridFooterDirective, DataGridHeaderDirective, | ||||
|     DataGridLoaderDirective] | ||||
| }) | ||||
| export class DataGridModule { } | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| <table [ngClass]="tableClasses"> | ||||
| <ng-container *ngIf="loading" [ngTemplateOutlet]="loadingTemplate"></ng-container>  | ||||
| 
 | ||||
| <table [ngClass]="tableClasses" style="min-height: 300px;"> | ||||
|   <thead> | ||||
|     <tr> | ||||
|       <th *ngFor="let header of gridHeaders" [attr.colspan]="columns.length"> | ||||
| @ -15,12 +17,7 @@ | ||||
|       </th> | ||||
|     </tr> | ||||
|   </thead> | ||||
|   <tbody *ngIf="loading"> | ||||
|     <tr> | ||||
|       <td [attr.colspan]="columns.length"><ng-content select="psDataGridLoader"></ng-content></td> | ||||
|     </tr> | ||||
|   </tbody> | ||||
|   <tbody *ngIf="latestResult&&!loading"> | ||||
|   <tbody *ngIf="!noData else noResultTemplate"> | ||||
|     <tr *ngFor="let rowModel of latestResult.data; let i = index"> | ||||
|       <td *ngFor="let column of columns"> | ||||
|         <ng-container *ngIf="hasCellTemplate(column)"> | ||||
| @ -44,3 +41,18 @@ | ||||
|     </tr> | ||||
|   </tfoot> | ||||
| </table> | ||||
| 
 | ||||
| <ng-template #loadingTemplate> | ||||
|   <ng-container *ngFor="let loader of loaders"> | ||||
|     <ng-container [ngTemplateOutlet]="loader.template"></ng-container> | ||||
|   </ng-container> | ||||
| </ng-template> | ||||
| <ng-template #noResultTemplate> | ||||
|   <tbody> | ||||
|     <tr> | ||||
|       <td [attr.colspan]="columns.length"> | ||||
|         <p style="text-align: center;">{{ noRecordsDisplayText }}</p> | ||||
|       </td> | ||||
|     </tr> | ||||
|   </tbody> | ||||
| </ng-template> | ||||
|  | ||||
| @ -1,27 +1,34 @@ | ||||
| import { Component, OnInit, ContentChildren, QueryList, Input, Output, EventEmitter } from '@angular/core'; | ||||
| import { Component, OnInit, ContentChildren, QueryList, Input, Output, EventEmitter, ContentChild, ChangeDetectorRef, OnDestroy } from '@angular/core'; | ||||
| import { IQueryExecutionResult, IQueryExecutionGroupResult, IDataSource } from '@poweredsoft/data'; | ||||
| import { DataGridColDirective } from '../directives/data-grid-col.directive'; | ||||
| import { DataGridHeaderDirective } from '../directives/data-grid-header.directive'; | ||||
| import { DataGridFooterDirective } from '../directives/data-grid-footer.directive'; | ||||
| import { DataGridLoaderDirective } from '../directives/data-grid-loader.directive'; | ||||
| import { Subscription } from 'rxjs'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'ps-data-grid', | ||||
|   templateUrl: './data-grid.component.html', | ||||
|   styleUrls: ['./data-grid.component.scss'] | ||||
| }) | ||||
| export class DataGridComponent implements OnInit { | ||||
| export class DataGridComponent implements OnInit, OnDestroy { | ||||
| 
 | ||||
|   latestResult: IQueryExecutionResult<any> & IQueryExecutionGroupResult<any>; | ||||
|   loading:boolean; | ||||
| 
 | ||||
|   @ContentChildren(DataGridColDirective) columnDefinitions: QueryList<DataGridColDirective>; | ||||
|   @ContentChildren(DataGridHeaderDirective) gridHeaders: QueryList<DataGridHeaderDirective>; | ||||
|   @ContentChildren(DataGridFooterDirective) gridFooters: QueryList<DataGridFooterDirective>; | ||||
|    | ||||
|   @ContentChildren(DataGridLoaderDirective) loaders: QueryList<DataGridLoaderDirective>; | ||||
|    | ||||
|   @Input() dataSource: IDataSource<any>; | ||||
|   @Input() tableClasses: any; | ||||
|   @Input() noRecordsText: string; | ||||
| 
 | ||||
|   private _columns: string[]; | ||||
|   loading:boolean; | ||||
|   private _dataSubscription: Subscription; | ||||
|   private _loadingSubscription: Subscription; | ||||
| 
 | ||||
|   @Input() set columns(value: string[]) { | ||||
|     this._columns = value; | ||||
|     this.columnsChange.emit(value); | ||||
| @ -32,19 +39,45 @@ export class DataGridComponent implements OnInit { | ||||
|   }   | ||||
| 
 | ||||
|   @Output() columnsChange:EventEmitter<string []> = new EventEmitter<string []>(); | ||||
|   constructor() { } | ||||
| 
 | ||||
|    | ||||
| 
 | ||||
|   get noData() { | ||||
|     return !this.latestResult || this.latestResult.totalRecords == 0;  | ||||
|   } | ||||
| 
 | ||||
|   get noRecordsDisplayText() { | ||||
|     return this.noRecordsText || 'No records'; | ||||
|   } | ||||
| 
 | ||||
|   constructor(private cdr: ChangeDetectorRef) {  | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   ngOnDestroy(): void { | ||||
|     this._dataSubscription.unsubscribe(); | ||||
|     this._loadingSubscription.unsubscribe(); | ||||
|   } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this.loading = true; | ||||
|     console.log(this.columnDefinitions); | ||||
|     this.dataSource.data$.subscribe(newData => { | ||||
|       this.loading=false; | ||||
|    | ||||
|     this._dataSubscription = this.dataSource.data$.subscribe(newData => { | ||||
|       this.latestResult = newData; | ||||
|     }); | ||||
| 
 | ||||
|     this._loadingSubscription = this.dataSource.loading$.subscribe(isLoading => { | ||||
|       this.loading = isLoading; | ||||
|       this.cdr.detectChanges(); | ||||
|     }); | ||||
| 
 | ||||
|     console.log(this.loaders); | ||||
|   } | ||||
| 
 | ||||
|   getColumn(columnName: string) { | ||||
|      | ||||
|     if (!this.columnDefinitions) | ||||
|       return null; | ||||
| 
 | ||||
|     const ret = this.columnDefinitions.find(t =>  | ||||
|     { | ||||
|       return t.columnName == columnName; | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| import { Directive } from '@angular/core'; | ||||
| import { Directive, TemplateRef } from '@angular/core'; | ||||
| 
 | ||||
| @Directive({ | ||||
|   selector: '[psDataGridLoader]' | ||||
| }) | ||||
| export class DataGridLoaderDirective { | ||||
| 
 | ||||
|   constructor() { } | ||||
|   constructor(public template: TemplateRef<any>) { } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -46,8 +46,11 @@ | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #theModal let-command let-loading="loading"> | ||||
|     Name | ||||
|     <input type="text" [attr.disabled]="loading" [(ngModel)]="command.name" placeholder="Enter a merchant name" class="form-control"> | ||||
|     Address | ||||
|     <input type="text" required [attr.disabled]="loading" [(ngModel)]="command.address" placeholder="Enter the merchant's address" class="form-control"> | ||||
|     <form ngNativeValidate  > | ||||
|         Name | ||||
|         <input type="text" required [disabled]="loading" name="name" [(ngModel)]="command.name"  placeholder="Enter a merchant name" class="form-control" > | ||||
|         Address | ||||
|         <input type="text" required [disabled]="loading" name="address" [(ngModel)]="command.address"  placeholder="Enter the merchant's address" class="form-control" >         | ||||
|     </form> | ||||
|      | ||||
| </ng-template> | ||||
| @ -1,7 +1,13 @@ | ||||
| 
 | ||||
|    <psbx-spinner psDataGridLoader></psbx-spinner> | ||||
|    | ||||
| <ps-data-grid [dataSource]="merchantDataSource" [(columns)]="columns" | ||||
|     tableClasses="table table-sm table-dark table-striped table-bordered"> | ||||
| 
 | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
|     <psbx-spinner *psDataGridLoader></psbx-spinner> | ||||
| 
 | ||||
|     <ng-container *psDataGridHeader> | ||||
|         <button class="btn-warning btn" psbxCommandModal commandTitle="Adding a new merchant" commandText="Add" | ||||
|             [dataSource]="merchantDataSource" command="addMerchant" [template]="theModal">Create a new record</button> | ||||
| @ -10,6 +16,18 @@ | ||||
|     <ng-container psDataGridCol="id"> | ||||
|         <div *psDataGridColHeader>ID</div> | ||||
|         <div *psDataGridCell="let model">{{model.id}}</div> | ||||
| 
 | ||||
|         <!-- <psfa-ds-sort-icon *psDataGridColSort [sortPath]="id" [dataSource]="merchantDataSource"> | ||||
| 
 | ||||
|         </psfa-ds-sort-icon>  --> | ||||
| 
 | ||||
|         <!-- <psbx-ds-text-filter *psDataGridCellFilter [dataSource]="merchantDataSource"></psbx-ds-text-filter> | ||||
|         <psdb-ds-date-filter *psDataGridCellFilter></psdb-ds-date-filter> | ||||
|         <psdb-ds-date-range-filter *psDataGridCellFilter></psdb-ds-date-range-filter> | ||||
|         <psbx-ds-number-filter *psDataGridCellFilter></psbx-ds-number-filter> | ||||
|         <psbx-ds-multi-select-filter [dataSource]="merchantDataSource" [selectDataSource]="selectDataSource" [valueField]="id"> | ||||
|             <ng-container *psSelectOption="let option">{{ option.name }}</ng-container> | ||||
|         </psbx-ds-multi-select-filter> --> | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <ng-container psDataGridCol="name"> | ||||
| @ -27,7 +45,6 @@ | ||||
|             <!-- <button class="btn-warning btn" psbxCommandModal [commandTitle]="'Change ' + model.name + ' name'" commandText="Update" | ||||
|             [dataSource]="merchantDataSource" command="changeMerchant" [model]="model" [template]="changeName">Change</button> --> | ||||
|             <button class="btn-danger btn" (click)="removeMerchant(model.id)">Remove</button> | ||||
|             | ||||
|         </ng-container> | ||||
|     </ng-container> | ||||
| 
 | ||||
| @ -48,9 +65,23 @@ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| <ng-template #theModal let-command let-loading="loading"> | ||||
|     Name | ||||
|     <input type="text" [attr.disabled]="loading" [(ngModel)]="command.name" placeholder="Enter a merchant name" class="form-control"> | ||||
|     Address | ||||
|     <input type="text" [attr.disabled]="loading" [(ngModel)]="command.address" placeholder="Enter the merchant's address" class="form-control"> | ||||
| </ng-template> | ||||
|  <ng-template #theModal let-command let-loading="loading"> | ||||
|         <label for="name">Name</label> | ||||
|         <input type="text" required [attr.disabled]="loading" [(ngModel)]="command.name" placeholder="Enter a merchant name"  | ||||
|                class="form-control"  > | ||||
|         <label for="address">Address</label> | ||||
|         <input type="text" required [attr.disabled]="loading" [(ngModel)]="command.address" placeholder="Enter the merchant's address"  | ||||
|               class="form-control" > | ||||
|          | ||||
| </ng-template>  | ||||
| 
 | ||||
| <!-- <ng-template #theModal let-command let-form let-loading="loading"> | ||||
|     <label for="name">Name</label> | ||||
|     <input type="text" required [attr.disabled]="loading" [(ngModel)]="command.name" name="name" placeholder="Enter a merchant name"  | ||||
|            class="form-control"  #nameField="ngModel" [class.field-error]="form.submitted && form.invalid">  | ||||
|     <label for="address">Address</label> | ||||
|     <input type="text" required [attr.disabled]="loading" [(ngModel)]="command.address" name="address" placeholder="Enter the merchant's address"  | ||||
|           class="form-control" #addressField="ngModel" [class.field-error]="form.submitted && form.invalid"> | ||||
|      | ||||
|      | ||||
| </ng-template> --> | ||||
| @ -0,0 +1,3 @@ | ||||
| .ng-invalid:not(form).ng-touched{ | ||||
|     border: 1px solid red; | ||||
| }  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user