微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Angular 中使日期字段具有反应性

如何解决在 Angular 中使日期字段具有反应性

我正在尝试将 datepicker 中的 ngx-bootstrap 组件设为自定义日期字段,以便我可以将某些功能和配置全球化。但我似乎无法在日期输入字段中捕获 Date 对象的值。

我的 date-field.ts(我正在重新使用文本字段中的一些设置。如果您看到文本字段组件的一些残余,请耐心等待。但我确定我的主要问题是我的组件不知道它是一个日期字段)

  import { Component,OnInit,forwardRef,Input } from '@angular/core';
  import { FormControl,ControlValueAccessor,NG_VALUE_ACCESSOR } from '@angular/forms';

  @Component({
    selector: 'date-field',templateUrl: './date-field.component.html',styleUrls: ['./date-field.component.scss'],providers:[
      {
        provide: NG_VALUE_ACCESSOR,multi: true,useExisting: forwardRef(() => DateFieldComponent),}
    ]
  })
  
  export class DateFieldComponent implements OnInit,ControlValueAccessor {

    public dateField = new FormControl("")
    private onChange: (name: string) => void;
    private onTouched: () => void

    @input() name: string;
    @input() label: string;
    @input() required: boolean;

    datepickerConfig = {
      dateInputFormat: 'ddd,MMMM Do YYYY',isAnimated: true,adaptivePosition: true,returnFocusToInput: true,containerClass: 'theme-dark-blue'
    } 

    constructor() { }

    ngOnInit() { }


    writeValue(obj: any): void {
      const date = Date
      this.dateField.setValue(new Date());
      console.log(date);
    }

    registerOnChange(fn: any): void {
      this.onChange = fn;
    }
    registerOnTouched(fn: any): void {
      this.onTouched = fn;
    }

    setdisabledState?(isdisabled: boolean): void {
      if (isdisabled) {
        this.dateField.disable();
      } else {
        this.dateField.enable();
      }
    }

    doinput() {
      this.onChange(this.dateField.value)    
    }

    doblur() {
      this.onTouched();
    }

  }

模板 HTML:

  <label
    *ngIf="label"
    for="{{name}}"
    class="col-auto col-form-label {{required ? 'required' : '' }}">
    {{label}}
  </label>
  <div class="col-expand relative">
    <input 
      type="text"
      class="form-control date-field"
      #dp="bsDatepicker"
      [formControl]="dateField"
      (input)="doinput()"
      (blur)="doblur()"
      ngModel
      bsDatepicker
      [bsConfig]="datepickerConfig"
      required="{{required}}">  
  </div>

在这样的父表单中使用它:

 <date-field
     name="dateChartered"
     label="Date local union chartered"
     formControlName="dateChartered"
     required="true">
 </date-field>

 <p><strong>Date chartered is:</strong> {{dateChartered}}</p>

解决方法

假设您在父组件中正确初始化了控制器中的 FormGroup 并在模板中正确使用它,那么您的组件中有两个主要错误。

首先,正如 Belle Zaid 所说,您应该从自定义日期选择器的 ngModel 中删除 <input>

其次,您将 doInput() 绑定到 (input),但只有在您输入输入字段时才会触发,(change) 也是如此。您应该绑定到 (bsValueChange),这是 BsDatepicker 公开的输出事件,这样更安全,除非您计划更新用户输入的值。

生成的模板将如下所示:

<label *ngIf="label"
       for="my-custom-datepicker"
       class="col-auto col-form-label {{required ? 'required' : '' }}">

  {{label}}

</label>


<div class="col-expand relative">
  <input id="my-custom-datepicker"
         type="text"
         class="form-control date-field"
         required="{{required}}"
         bsDatepicker
         [formControl]="dateField"
         [bsConfig]="datepickerConfig"
         (blur)="doBlur()"
         (bsValueChange)="doInput()">  
</div>

完成这两项更改后,您会注意到控制台中出现错误:

ExpressionChangedAfterItHasBeenCheckedError:表达式在它被 检查。 'ng-pristine' 的先前值:'true'。当前值:'false'.. 查找更多 在https://angular.io/errors/NG0100

这是因为在 this.dateField.setValue(obj) 中调用 writeValue 也会触发 (bsValueChange),从而触发 doInput()。为了解决这个问题,您可以像下面这样编辑代码:


private componentInit = false;

// ...

doInput() {
  if (!this.componentInit) {
    this.componentInit = true;
    return;
  }

  this.onChange(this.dateField.value);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。