Angular 2 проверяет, что один ввод даты равен или предшествует другому

У меня есть два входа, которые заполнены двумя Angular 2 Bootstrap datepickers. Я хочу, чтобы моя кнопка, соответствующая FormGroup, была отключена, если startDate находится после (не до или равно) endDate. Прямо сейчас, если я выберу startDate позже, чем endDate, кнопка отправки останется активной. Но если я затем нажму вторую кнопку календаря, чтобы всплыло второе datepicker, кнопка отправки станет неактивной (на самом деле мне не нужно выбирать endDate). Я проверил с помощью консоли, и startDate, endDate и error все меняются и меняются на правильные значения в нужное время без ошибок, это просто отключение кнопки отправки, у которой отключено «время».

<form class="form-inline">
<div>
<div class="form-group" [ngClass]="{'has-error':!secondForm.controls['startDate'].valid && secondForm.controls['startDate'].touched}">
  <label>Start Date:</label>
  <input style="width:250px" [value]="getDate('start')" class="form-control" type="text" [formControl]="secondForm.controls['startDate']">
</div>
<div style="display:inline-block">
  <ngb-datepicker id="special" *ngIf="startCheck;" [(ngModel)]="startDate" (ngModelChange)="showDatePick(0)" [ngModelOptions]="{standalone: true}"></ngb-datepicker>
</div>
<button type="button" class="btn icon-calendar" (click)="showDatePick(0)"></button>
<div class="form-group" [ngClass]="{'has-error':!secondForm.controls['endDate'].valid && secondForm.controls['endDate'].touched}">
  <label>End Date:</label>
  <input style="width:250px" [value]="getDate('end')" class="form-control" type="text" [formControl]="secondForm.controls['endDate']">
</div>
<div style="display:inline-block">
  <ngb-datepicker id="special" *ngIf="endCheck;" [(ngModel)]="endDate" (ngModelChange)="showDatePick(1)" [ngModelOptions]="{standalone: true}"></ngb-datepicker>
</div>
<button type="button" class="btn icon-calendar" (click)="showDatePick(1)"></button>
<button type="submit" class="btn icon-search" [disabled]="!secondForm.valid || error==true"></button>
</div>
</form>

Соответствующий машинописный текст:

import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
import {DatePipe} from "@angular/common";
import * as moment from 'moment';

@Component({
selector: 'calendar-pick',
styleUrls: ['../app.component.css'],
templateUrl: './calendarpick.component.html',
providers: [DatePipe]
})

export class CalendarPickComponent {
public error: boolean = false;
public dt: NgbDateStruct;
public dt2: NgbDateStruct;
public startCheck: boolean = false;
public endCheck: boolean = false;
secondForm : FormGroup;

public constructor(fb: FormBuilder, private datePipe: DatePipe) {
this.secondForm = fb.group({
  'startDate' : [this.dt, Validators.required],
  'endDate' : [this.dt2, Validators.required]
})
this.secondForm.valueChanges.subscribe( (form: any) => {
    console.log('form changed to:', form);
  }
);
}

public getDate(dateName: string) {
let workingDateName = dateName + 'Date';
let timestamp = this[workingDateName] != null ? new Date(this[workingDateName].year, this[workingDateName].month-1, this[workingDateName].day).getTime() : new Date().getTime();
this.secondForm.controls[dateName + 'Date'].setValue(this.datePipe.transform(timestamp, 'longDate'));
}

public showDatePick(selector):void {
if(selector === 0) {
  this.startCheck = !this.startCheck
} else {
  this.endCheck = !this.endCheck;
}
this.periodValidator(this.secondForm);
}

periodValidator(formGroup:FormGroup) {
let s = new Date(formGroup.value.startDate);
let e = new Date(formGroup.value.endDate);
let stDt = moment(s);
let endDt = moment(e);
if (stDt > endDt) {
  this.error = true;
}else {
  this.error = false;
}
}

}

person Drew13    schedule 04.11.2016    source источник


Ответы (2)


Вы можете определить собственный валидатор и назначить его группе форм в целом следующим образом:

endDateAfterOrEqualValidator(formGroup): any {
    var startDateTimestamp, endDateTimestamp;
    for(var controlName in formGroup.controls) {
      if(controlName.indexOf("startDate") !== -1) {
        startDateTimestamp = Date.parse(formGroup.controls[controlName].value);
      }
      if(controlName.indexOf("endDate") !== -1) {
        endDateTimestamp = Date.parse(formGroup.controls[controlName].value);
      }
    }
    return (endDateTimestamp < startDateTimestamp) ? { endDateLessThanStartDate: true } : null;
  }

Это проверит временные метки элемента управления и вернет что-то, если оно неверно, и null, если оно действительно.

this.secondForm = fb.group({
    'startDate' : ['', Validators.required],
    'endDate'  : ['', Validators.required]
  },
  {validator: this.endDateAfterOrEqualValidator});

Я полагаю, что если вы не собираетесь добавлять какие-либо дополнительные элементы управления, вы можете жестко запрограммировать назначения временных меток вместо проверки элементов управления на наличие нужных вам значений.

Планкер: http://plnkr.co/edit/Yow6DMd2soBXwJ2oGOFu?p=preview

person silentsod    schedule 07.11.2016
comment
Я также хочу добавить небольшое предупреждающее сообщение, если возникает эта ошибка проверки. Это просто тег div, но возникают проблемы с его отображением с помощью *ngIf. Я попытался установить this.error=true; в функции endDateAfterOrEqualValidator, а затем добавить *ngIf="error" в тег div. Также пробовал *ngIf="secondForm.hasError('endDateLessThanStartDate')", но это тоже не сработало. - person Drew13; 07.11.2016
comment
Смог использовать второе решение после помещения enableProdMode() в мой файл main.ts после моих операторов импорта - person Drew13; 07.11.2016
comment
Есть ли менее хакерский способ сделать это? - person Drew13; 07.11.2016
comment
<div [hidden]="!secondForm.hasError('endDateLessThanStartDate')">show me</div> работает без ошибок (и без enableProMode()), менее хакерский, но все же заставляет задуматься, есть ли лучший способ все настроить. - person silentsod; 07.11.2016

Для моего компонента выбора даты я использовал этот код в качестве валидатора.

if(this.dateFrom && this.dateTo) {

    var d1 = Date.parse(this.dateTo);
    var d2 = Date.parse(this.dateFrom);

       if (d1 > d2) {
           this.error = true;
       }
}

Это должно работать для вас, если оно находится в стандартном формате javascript или моментальной даты. Также в операторе if при условии, что вы можете установить переменную error = true, и это вызовет сообщение об ошибке следующим образом.

<button [disabled]="error"></button>

Надеюсь, этот плункер поможет: пример плунжера

person DavidR2106    schedule 04.11.2016
comment
Спасибо за предложение, но на самом деле не помогает, так как я работаю с машинописным текстом, и мне нужна проверка для координации с отключением и включением моей кнопки @DavidR2016 - person Drew13; 04.11.2016
comment
Я хорошо работаю в машинописи. и [disabled]=ошибка с приведенным выше кодом должна отсортировать ее. - person DavidR2106; 04.11.2016
comment
Извините, но я просто немного запутался в том, где в моем машинописном тексте я добавляю этот код, а также тег div и [disabled]="error" - person Drew13; 04.11.2016
comment
Также не уверен в моем формате даты, так как он печатает, например, Friday, November 4, 2016 - person Drew13; 04.11.2016
comment
Извините, в основном функция periodValidator такая же. если эта логика работает, вместо возврата null установите this.error = true. а затем, когда у вас есть кнопка, которая уже имеет атрибут [disabled], просто добавьте «&& error» рядом с существующим кодом. - person DavidR2106; 04.11.2016
comment
вот пример для вас, чтобы попробовать plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=preview - person DavidR2106; 04.11.2016
comment
Я отредактировал исходный код. Обратите внимание на [disabled]="!secondForm.valid && error" в моей кнопке, добавление public error: boolean; вверху класса, добавление , {}, this.periodValidator в конце конструктора FormBuilder и полное изменение функции periodValidator. Я уверен, что это как-то связано с тем, как я вызываю/использую эту функцию. - person Drew13; 04.11.2016
comment
Я снова отредактировал свой код, в котором моя функция showDatePick вызывает periodValidator, которая имеет правильную логику (я проверил, напечатав this.error в консоль). У меня все еще есть [disabled] в моей кнопке, проверяющей error на истинность, но она все еще не работает. Какие-либо предложения? - person Drew13; 07.11.2016
comment
Итак, console.log показывает, что для него установлено значение true? единственное, что я вижу, это то, что у вас [disabled]=!secondForm.valid || error==true, когда должно быть [disabled]=!secondForm.valid || ошибка - person DavidR2106; 07.11.2016
comment
На самом деле похоже, что это работает, но единственное, что после выбора первой даты, я должен нажать на другую datepicker, чтобы она заметила. - person Drew13; 07.11.2016
comment
Кажется, что periodValidator установит для ошибки значение true только в том случае, если у него есть как начальное, так и конечное значения, что означает, что вам придется взаимодействовать с обоими средствами выбора даты. - person DavidR2106; 07.11.2016
comment
Ну, это устанавливает error в true, выбирая только первую дату. Мне даже не нужно выбирать вторую дату, мне просто нужно открыть datepicker, чтобы кнопка стала неактивной. - person Drew13; 07.11.2016
comment
Попробуйте обернуть оператор if, который устанавливает статус ошибки, в другой оператор if, чтобы проверить существование значений перед выполнением кода. например, if(stDt && endDt) {ваше существующее выражение if} - person DavidR2106; 07.11.2016
comment
Давайте продолжим обсуждение в чате. - person Drew13; 07.11.2016