Angular 2表单验证开始日期<=结束日期

Posted

技术标签:

【中文标题】Angular 2表单验证开始日期<=结束日期【英文标题】:Angular 2 form validations start date <= end date 【发布时间】:2017-10-02 10:19:02 【问题描述】:

我正在尝试添加验证,以使结束日期不能早于开始日期。不幸的是,我不知道该怎么做,而且到目前为止我在互联网上也没有找到任何有用的建议。我的表单如下所示:

editAndUpdateForm(tageler: Tageler) 
    this.tageler = tageler;
    this.tagelerForm = this.fb.group(
      title: [this.tageler.title, Validators.required],
      text: this.tageler.text,
      group: [[this.tageler.group], Validators.required],
      date_start: new Date(this.tageler.start).toISOString().slice(0, 10),
      date_end: new Date(this.tageler.end).toISOString().slice(0, 10),
      ...
    );
    this.tagelerForm.valueChanges
       .subscribe(data => this.onValueChanged(data));
    

到目前为止我的验证:

onValueChanged(data?: any) 
    if (!this.tagelerForm) 
      return;
    
    const form = this.tagelerForm;

    for (const field in this.formErrors) 

    // clear previous error message (if any)
      this.formErrors[field] = '';
      const control = form.get(field);

      if (control && control.dirty && !control.valid) 
        const messages = this.validationMessages[field];
        for (const key in control.errors) 
          this.formErrors[field] += messages[key] + ' ';
        
      
    


validationMessages = 
    'title': 
      'required': 'Geben Sie bitte einen Namen ein.',
    ,
    'group': 
      'required': 'Wählen Sie bitte eine Gruppe aus.'
    ,
    'bringAlong': 
      'required': 'Bitte Feld ausfüllen.'
    ,
    'uniform': 
      'required': 'Bitte Feld ausfüllen.'
    ,
;

formErrors = 
    'title': 'Geben Sie bitte einen Namen ein.',
    'group': 'Wählen Sie bitte eine Gruppe aus.',
    'bringAlong': 'Bitte Feld ausfüllen',
    'uniform': 'Bitte Feld ausfüllen',
;

表单控件“date_start”和“date_end”包含“dd.MM.yyyy”形式的日期字符串,我希望“date_end”大于或等于“date_start”。

我想直接显示错误信息(我的html代码是这样的:)

<label for="formControlName_date_end" class="col-3 col-form-label">Ende:</label>
      <div class="col-5">
        <input id="formControlName_date_end" class="form-control" formControlName="date_end" type="date" value="tageler.end | date: 'yyyy-MM-dd'">
      </div>
      <div *ngIf="formErrors.date_end" class="alert alert-danger">
         formErrors.date_end 
      </div>

有人可以帮我吗?

谢谢!

【问题讨论】:

【参考方案1】:

根据 santiagomaldonado 的回答,我创建了一个通用的 ValidatorFn,它可以在具有动态返回值的多个反应式表单中使用。

export class DateValidators 
    static dateLessThan(dateField1: string, dateField2: string, validatorField:  [key: string]: boolean ): ValidatorFn 
        return (c: AbstractControl):  [key: string]: boolean  | null => 
            const date1 = c.get(dateField1).value;
            const date2 = c.get(dateField2).value;
            if ((date1 !== null && date2 !== null) && date1 > date2) 
                return validatorField;
            
            return null;
        ;
    

导入验证器并在您的表单组验证器中像这样使用它。

    this.form = this.fb.group(
        loadDate: null,
        deliveryDate: null,
    ,  validator: Validators.compose([
        DateValidators.dateLessThan('loadDate', 'deliveryDate',  'loaddate': true ),
        DateValidators.dateLessThan('cargoLoadDate', 'cargoDeliveryDate',  'cargoloaddate': true )
    ]));

现在您可以在 HTML 中使用验证。

<md-error *ngIf="form.hasError('loaddate')">Load date must be before delivery date</md-error>

【讨论】:

【参考方案2】:

您也可以使用响应式表单来做到这一点。 FormBuilder API 允许您添加自定义验证器。

额外参数映射的有效键是 validator 和 asyncValidator

例子:

import  Component   from '@angular/core';
import  FormGroup, FormBuilder, Validators  from '@angular/forms';

@Component(
  selector: 'reactive-form',
  templateUrl: './reactive-form.html'
)
export class ReactiveFormComponent 
  
  form: FormGroup

  constructor(private fb: FormBuilder)
    this.createForm();
  

  createForm() 
    this.form = this.fb.group(
      dateTo: ['', Validators.required ],
      dateFrom: ['', Validators.required ]
    , validator: this.dateLessThan('dateFrom', 'dateTo'));
  
  
  dateLessThan(from: string, to: string) 
   return (group: FormGroup): [key: string]: any => 
    let f = group.controls[from];
    let t = group.controls[to];
    if (f.value > t.value) 
      return 
        dates: "Date from should be less than Date to"
      ;
    
    return ;
   
 
      

请注意,我正在比较输入日期和起始日期的值与 >,但默认情况下这是比较字符串。 在现场示例中,我使用 angular-date-value-accessor 并导入指令 useValueAsDate。

<input formControlName="dateFrom" type="date" useValueAsDate />

使用此指令 group.controls[from].value 和 group.controls[to].value 返回 Date 然后我可以将它们与 <.>

Live example in plunkr

感谢Dave's answer

【讨论】:

在 Angular 5 中似乎不起作用。你的 plunker 也坏了。【参考方案3】:

我的是 angular7 + ngprime(用于日历)

(*如果您不想要 ngprime,只需将日历部分替换为其他人。)

请参阅下面的代码进行日期验证。

我的代码有额外的验证 选择开始日期后,我会在结束数据的日历中阻止前几天 所以结束日期总是比那个晚。

如果您不想阻止日期,请删除 [minDate] 部分。 它也有效。

> 组件

export class test implements OnInit 

  constructor()  

  defaultDate: Date = new Date();
  checkDate = true;
  form: FormGroup;

  today: Date = new Date(); //StartDate for startDatetime
  startDate: Date = new Date();  //StartDate for endDatetime

  initFormControls(): void 
    this.today.setDate(this.today.getDate());
    this.startDate.setDate(this.today.getDate()); //or start date + 1 day

    this.form = new FormGroup(
      startDatetime: new FormControl('', [Validators.required]),
      endDatetime: new FormControl('', [Validators.required])
    ,
       validators: this.checkDateValidation );
  

  checkDateValidation: ValidatorFn = (control: FormGroup): ValidationErrors | null => 
    try 

      let startingDatefield = control.get('startDatetime').value;

      this.startDate = new Date(startingDatefield); //new Date(startingDatefield).getDate()
      let endingDatefield = control.get('endDatetime').value;

      if (this.today >= startingDatefield)  //compare to current date 
        console.log("Please set a Start Date that is on or after Current Date and Time.");
        return  'effectiveStartDatetime': false ;

       else
        if (startingDatefield > endingDatefield && endingDatefield) 
          console.log("Please set an End Date and Time that is after the Start Date and Time.");
          return ;

         else 
          return ;
        
     catch (err) 
    
  ;



  onSubmit() 

    //if form is not valid
    if (!this.form.valid) 
      console.log(" Please fill in all the mandatory fields");

      // do sth
    return;
    


    //if form is valid
    //do sth

  


  ngOnInit() 
    this.initFormControls();
  

> HTML

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <div>
    <div>
      <p-button type="submit" label="submit"></p-button>
    </div>
  </div>
  <div>
    <p>Start Date/Time"</p>
    <div>
      <p-calendar formControlName="startDatetime" appendTo="body" showTime="true" hourFormat="24" stepMinute="30"
        showSeconds="false" dateFormat="yy-mm-dd" [minDate]="today"></p-calendar>
      <div
        *ngIf="form.get('startDatetime').invalid && (form.get('startDatetime').dirty || form.get('startDatetime').touched)">
        <div *ngIf="form.get('startDatetime').hasError('required')">
        </div>
      </div>
    </div>

    <p>End Date/Time</p>
    <div>
      <p-calendar formControlName="endDatetime" appendTo="body" showTime="true" hourFormat="24" stepMinute="30"
        showSeconds="false" dateFormat="yy-mm-dd" [minDate]="startDate"></p-calendar>
      <div *ngIf="form.get('endDatetime').invalid && (form.get('endDatetime').dirty || form.get('endDatetime').touched)">
        <div *ngIf="!checkDate || form.get('endDatetime').hasError('required')">
        </div>
      </div>
    </div>
  </div>

</form>

【讨论】:

【参考方案4】:

我正在使用时刻,并在 Angular 7 中比较和验证日期,我使用此功能:

datesValidator(date1: any, date2: any): [key:string]:any | null 
    return (group: FormGroup):  [key: string]: any  | null => 
        let start = group.controls[date1].value;
        let end = group.controls[date2].value;
        let datum1 = _moment(start).startOf('day');
        let datum2 = _moment(end).startOf('day');
        if (_moment(datum1).isSameOrAfter(datum2)) 
           this.alert.red("Error: wrong period!"); //popup message
           return  'error': 'Wrong period!' ;        
        
        return null; //period is ok, return null
    ;

【讨论】:

【参考方案5】:

创建一个表单组。让控件成为表单组的一部分。

       new FormGroup(   
        startDate: this.fb.group(
            dateInput: [value: "", startDateValidator()]
        ),   
        endDate: this.fb.group(
            dateInput: ["", endDateValidator()]
        )  
    , startDateCannotBeLessThanEndDateValidator());   

        startDateCannotBeLessThanEndDateValidator(formGroup: FormGroup) 

             let startDate = formGroup.get("startDate");   
            let endDate = formGroup.get("endDate");
            // compare 2 dates 
        

【讨论】:

【参考方案6】:

我们不能在验证中这样做,因为我们需要两个控制值,即 startdate 和 enddate 进行比较。所以最好在你的组件中比较两个日期

error:any=isError:false,errorMessage:'';

compareTwoDates()
   if(new Date(this.form.controls['date_end'].value)<new Date(this.form.controls['date_start'].value))
      this.error=isError:true,errorMessage:'End Date can't before start date';
   

在你的 html 中

<label for="formControlName_date_end" class="col-3 col-form-label">Ende:</label>
<div class="col-5">
      <input id="formControlName_date_end" class="form-control" formControlName="date_end" type="date" value="tageler.end | date: 'yyyy-MM-dd'" (blur)="compareTwoDates()">
</div>
<div *ngIf="error.isError" class="alert alert-danger">
    error.errorMessage 
</div>

【讨论】:

虽然显示错误信息,但表单验证仍然返回“有效”,有没有办法影响真正的表单验证? 这只会通知我们选择较小的结束日期然后开始数据的错误,但不会阻止提交表单本身。

以上是关于Angular 2表单验证开始日期<=结束日期的主要内容,如果未能解决你的问题,请参考以下文章

Angular Material matDatepicker 和 Textarea 作为表单的一部分

为 2 Datepicker 开始日期和结束日期设置验证 javascript

Angular 2 更改前后

按较早日期验证两个日期时间本地字段?

js验证开始日期不能大于结束日期?

SQL 按键重复开始和结束日期