问题描述
我正在尝试将 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);
}