Reputation: 11709
I am building component in angular in which I want start date to be greater than end date. I am wondering what changes I need to make in my HTML and TS codes to get it done. The snippets of HTML and TS codes which I am using are:
HTML:
<form class="unavailability-form" [formGroup]="unavailabilityForm" *ngIf="loaded">
<div class="component-title" matDialogTitle>
{{'PORTAL.TEXTUNAVAILABILITY' | translate}}
</div>
<mat-toolbar>
<div class="container"
fxLayout="row"
fxLayout.xs="column"
fxLayoutGap.xs="0">
<div>
<h1>{{componentTitle}}</h1>
</div>
</div>
</mat-toolbar>
<mat-dialog-content>
<div class="container" fxLayout="row" fxLayout.xs="column" fxLayoutGap.xs="0" fxLayoutGap="10px">
<div class="item item-1" fxFlex="50%" fxFlexOrder="1">
<mat-form-field>
<input matInput [matDatepicker]="picker" placeholder="{{'PORTALSTARTDATE' | translate}}" type="text" formControlName="startDate" [(ngModel)]="availability.startDate" [readonly]="!componentPermission.writePermission">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
<div class="item item-2" fxFlex="50%" fxFlexOrder="1">
<mat-form-field>
<input matInput [matDatepicker]="picker" placeholder="{{'PORTAL.ENDDATE' | translate}}" type="text" formControlName="endDate" [(ngModel)]="availability.endDate" [readonly]="!componentPermission.writePermission">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
</div>
<div class="item item-1" fxFlex="50%" fxFlexOrder="1">
<mat-form-field>
<input matInput placeholder="{{'PORTAL.UNAVAILABILITYREASON' | translate}}" type="text" formControlName="unavailabilityReason" [(ngModel)]="availability.unavailabilityReason" [readonly]="!componentPermission.writePermission">
</mat-form-field>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<div class="container" fxLayout="row" fxLayout.xs="column" fxLayoutGap.xs="0">
<div class="item item-1" fxFlex="100%">
<button mat-raised-button color="primary" [disabled]="!locationForm.valid || !componentPermission.writePermission" (click)="onSave()">{{'PORTAL.CONFIRM' | translate}}</button>
<button mat-raised-button [matDialogClose]="canceled" color="primary">{{'PORTAL.CANCEL' | translate}}</button>
</div>
</div>
</mat-dialog-actions>
</form>
TS:
validateForm() {
this.unavailabilityForm = this.formBuilder.group({
'startDate': [''],
'endDate': [''],
'unavailabilityReason': ['']
});
}
In the above code, {{PORTAL.___}} text refers to the value from the database.
Upvotes: 2
Views: 20936
Reputation: 36
you can check out my library ng-swiss-army-knife which has this form validator inside (and many other useful javascript/typescript/angular stuff) https://github.com/nickwinger/ng-swiss-army-knife
Upvotes: 0
Reputation: 41
With reactive forms, here is how i do it.
deploymentSignOffDatesValidator(g: FormGroup) {
return g.get('dateOfSignOff').value > g.get('dateOfDeployment').value ? null : {'unsequencial': true};
}
createEditUserForm(item: SaveUser) {
if (!item) {
item = {
dateOfDeployment: '',
dateOfSignOff: '',
}
}
this.userEditForm = this.fb.group({
dateOfDeployment: [item.dateOfDeployment, Validators.required],
dateOfSignOff: [item.dateOfSignOff]
}, {validator: this.deploymentSignOffDatesValidator});
<div class="col-xl-3 col-lg-6 col-md-12">
<fieldset class="form-group">
<label for="dateOfSignOff">Date of SignOff:</label>
<input
class="form-control"
placeholder="Date of SignOff"
bsDatepicker
formControlName="dateOfSignOff"
[bsConfig]="{ dateInputFormat: 'YYYY-MM-DD', containerClass: 'theme-dark-blue' }"
[ngClass]="{'is-invalid': userEditForm.get('dateOfSignOff').errors && (formDir.submitted || userEditForm.get('dateOfSignOff').touched) || userEditForm.hasError('unsequencial') && userEditForm.get('dateOfSignOff').touched}">
<div class="" *ngIf="userEditForm.hasError('unsequencial') && userEditForm.get('dateOfSignOff').touched">The Deploymnet Date must be less than Sign Off Date</div>
</fieldset>
</div>
Upvotes: 0
Reputation: 5332
Please note that you cannot use ngModel
within your form. You have to feed form from your component with data. Here is form with removed ngModel
:
<mat-dialog-content>
<form [formGroup]="unavailabilityForm " novalidate fxFlex>
<div class="container" fxLayout="row" fxLayout.xs="column" fxLayoutGap.xs="0" fxLayoutGap="10px">
<div class="item item-1" fxFlex="50%" fxFlexOrder="1">
<mat-form-field>
<input matInput [matDatepicker]="picker" placeholder="{{'PORTALSTARTDATE' | translate}}" type="text" formControlName="startDate" [readonly]="!componentPermission.writePermission">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
<div class="item item-2" fxFlex="50%" fxFlexOrder="1">
<mat-form-field>
<input matInput [matDatepicker]="picker" placeholder="{{'PORTAL.ENDDATE' | translate}}" type="text" formControlName="endDate" [readonly]="!componentPermission.writePermission">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
</div>
<div class="item item-1" fxFlex="50%" fxFlexOrder="1">
<mat-form-field>
<input matInput placeholder="{{'PORTAL.UNAVAILABILITYREASON' | translate}}" type="text" formControlName="unavailabilityReason" [readonly]="!componentPermission.writePermission">
</mat-form-field>
</div>
</form>
</mat-dialog-content>
Then you need to initialize form and add FormGroup level validator to your group. Also I feed data to your form:
initForm() {
this.unavailabilityForm = this.formBuilder.group({
'startDate': [availability.startDate],
'endDate': [availability.endDate],
'unavailabilityReason': [availability.unavailabilityReason]
}, validateDate);
}
Your custom validator function in FormGroup
will be validateDate
.
Custom validator function should be like this:
function validateDate(group: FormGroup) {
///TODO: Implement some better validation logic
const invalid = group.get('startDate').value > group.get('endDate').value;
///TODO: Implement some logic to mark controls dirty if is necessary.
return invalid ? { 'invalidDate': true } : null;
}
In custom validator on FormGroup
level you can you can access to all controls form that group and perform validation. Please note that value of your form will be string so, if you are working with Date
you will need better logic to compare dates.
Also please not that group level validator maybe will not display validation feedback, so you will need manually to mark controls to be dirty if is necessary.
Upvotes: 2