反应形式的 NgbDatepicker 形式:设置初始值
NgbDatepicker in Reactive Forms with formly: Set Initial Value
我正在尝试以 angular 反应形式使用 ngbDatepicker,并希望能够显示初始值。
我的问题是 with the crucial difference, that I am also using formly,一个自动生成表单的 angular 包。由于原始问题的答案是基于生成一个新的 formControl 并将其添加到表单中,在我的例子中,这是通过 formly 完成的,这就是我苦苦挣扎的原因。
“组件”通常在您要输入新值时起作用(因为这会触发我用来更改模型值的事件),但初始值显示不正确。虽然模型总是具有例如值“2020-07-05”如果使用占卜检查,则永远不会显示在输入字段中。如果我将模型中的日期转换为 ngOnInit() 中的 NgbDate ({year, month, day}),这仍然成立。
Formly 调用我的自定义组件(定义如下),它只包含字段并将预先存在的表单控件(包括模型)和字段配置绑定到输入字段。该组件本身并没有做太多事情,它包含 ngbDatepicker 所必需的 HTML 和一个函数,该函数在选择日期时将其从 NgbDate ({year, month, day}) 转换为字符串 ( “yyyy-mm-dd”)并确保将其存储在模型中而不是 NgbDate 中。当您单击 fa-calendar 图标时,它还会打开日期选择器:
//formly-datepicker.component.html
<div class="form-group" [ngClass]="{'d-none': to.hidden}">
<!-- Heading -->
<!-- to = TemplateOptions -->
<label for="datepicker">
<strong>
{{to.label}}
<span *ngIf="to.required">*</span>
</strong>
</label>
<!-- Input -->
<div class="input-group">
<input
class="form-control"
placeholder="yyyy-mm-dd"
name="datepicker"
[formControl]="formControl"
[formlyAttributes]="field"
ngbDatepicker
#datepickerInput="ngbDatepicker"
(dateSelect)="inputDateToField($event)"
>
<div class="input-group-append">
<div class="btn btn-outline-light fa fa-calendar" (click)="datepickerInput.toggle()"></div>
</div>
</div>
</div>
<ng-template #customDay let-date>
<div class="datepicker-day btn-light">
{{ date.day }}
</div>
</ng-template>
//formly-datepicker.component.ts
import { Component, } from '@angular/core';
import { NgbDate } from '@ng-bootstrap/ng-bootstrap';
import { FieldType } from '@ngx-formly/core';
@Component({
selector: 'app-formly-datepicker',
templateUrl: './formly-datepicker.component.html',
styleUrls: ['./formly-datepicker.component.scss']
})
export class FormlyDatepickerComponent extends FieldType{
inputDateToField(event: NgbDate){
this.model.session_date = `${event.year}-${event.month}-${event.day}`;
}
}
我试过在 ngOnInit() 和 ngAfterViewInit() 中操作模型,我试过设置 startDate,但在这种情况下似乎没有任何帮助。我在这里做什么?
我强烈建议您更新 NgBootstrap 和 Formly 的配置(如果您还没有更新的话):
- 不要在组件中使用
inputDateToField
方法,而是创建 NgBootstrap 为 NgbDatePicker 推荐的 two services (parser and adapter) 方法。解析器将维护您在 model
中指定的格式,适配器将再次根据您的自定义显示 UI 中的日期。例如。我使用解析器转换后端提供的 ISO 字符串,以便在我的 model
中将其保存为 'YYYY-MM-DD',并使用适配器将其显示为 'DD-MM-YYYY'
- 无论你在哪里导入
FormlyModule
像这样更新配置(如果它不在 AppModule 中,你可能必须使用 forChild
):
FormlyModule.forRoot({types: [{ name: 'date', component: FormlyDatepickerComponent, extends: 'input'}]})
- 在您的
FormlyDatepickerComponent
模板中,添加 type="text"
(可选)。
你可以采取两种方法:
1.-创建表单时使用 NgbDateStruct 作为默认值
//I imagine you has an object "data" with a property "date"
//in the way yyyy-mm-dd and create the field as
{
key: 'date',
type: 'input',
defaultValue: {
year:+data.date.substr(0,4),
month:+data.date.substr(5,2),
day:+data.date.substr(8,2)
},
templateOptions: {
label: 'First Name (initialized via default value)',
},
},
在这种情况下,您总是管理“日期”一个具有属性年月日的对象,是的,FormControl 可以存储一个对象,它不是“extrange”
2.- 使用管理字符串的自定义适配器。这有点复杂。您需要创建两个 class:
CustomAdepter
@Injectable()
export class CustomAdapter extends NgbDateAdapter<string> {
readonly DELIMITER = '-';
fromModel(value: string | null): NgbDateStruct | null {
if (value) {
let date = value.split(this.DELIMITER);
return {
day : parseInt(date[2], 10),
month : parseInt(date[1], 10),
year : parseInt(date[0], 10)
};
}
return null;
}
toModel(date: NgbDateStruct | null): string | null {
return date ? date.year+ this.DELIMITER+('00'+date.month).slice(-2) + this.DELIMITER + ('00'+date.day).slice(-2) : null;
}
}
和 CustomDateParserFormatter(当您输入时创建 ngbDateStructurt)
@Injectable()
export class CustomDateParserFormatter extends NgbDateParserFormatter {
readonly DELIMITER = '-';
parse(value: string): NgbDateStruct | null {
if (value) {
const separator=value.indexOf(".")>=0?".":value.indexOf("-")>=0?"-":value.indexOf("/")>=0?"/":null
if (separator)
{
let date = value.split(separator);
return {
day : parseInt(date[2], 10),
month : parseInt(date[1], 10),
year : parseInt(date[0], 10)
};
}
}
return null;
}
format(date: NgbDateStruct | null): string {
return date ? date.year+ this.DELIMITER+('00'+date.month).slice(-2) + this.DELIMITER + ('00'+date.day).slice(-2) : "";
}
}
然后在你的组件中你需要在你的模块中添加作为提供者(你也可以在你的组件中添加作为提供者)
providers: [
{provide: NgbDateAdapter, useClass: CustomAdapter},
{provide: NgbDateParserFormatter, useClass: CustomDateParserFormatter}
]
现在您可以使用,您的模型或 formControl 将是一个字符串
一个forked stackblitz the example in ng-bootstrap
我正在尝试以 angular 反应形式使用 ngbDatepicker,并希望能够显示初始值。
我的问题是
“组件”通常在您要输入新值时起作用(因为这会触发我用来更改模型值的事件),但初始值显示不正确。虽然模型总是具有例如值“2020-07-05”如果使用占卜检查,则永远不会显示在输入字段中。如果我将模型中的日期转换为 ngOnInit() 中的 NgbDate ({year, month, day}),这仍然成立。
Formly 调用我的自定义组件(定义如下),它只包含字段并将预先存在的表单控件(包括模型)和字段配置绑定到输入字段。该组件本身并没有做太多事情,它包含 ngbDatepicker 所必需的 HTML 和一个函数,该函数在选择日期时将其从 NgbDate ({year, month, day}) 转换为字符串 ( “yyyy-mm-dd”)并确保将其存储在模型中而不是 NgbDate 中。当您单击 fa-calendar 图标时,它还会打开日期选择器:
//formly-datepicker.component.html
<div class="form-group" [ngClass]="{'d-none': to.hidden}">
<!-- Heading -->
<!-- to = TemplateOptions -->
<label for="datepicker">
<strong>
{{to.label}}
<span *ngIf="to.required">*</span>
</strong>
</label>
<!-- Input -->
<div class="input-group">
<input
class="form-control"
placeholder="yyyy-mm-dd"
name="datepicker"
[formControl]="formControl"
[formlyAttributes]="field"
ngbDatepicker
#datepickerInput="ngbDatepicker"
(dateSelect)="inputDateToField($event)"
>
<div class="input-group-append">
<div class="btn btn-outline-light fa fa-calendar" (click)="datepickerInput.toggle()"></div>
</div>
</div>
</div>
<ng-template #customDay let-date>
<div class="datepicker-day btn-light">
{{ date.day }}
</div>
</ng-template>
//formly-datepicker.component.ts
import { Component, } from '@angular/core';
import { NgbDate } from '@ng-bootstrap/ng-bootstrap';
import { FieldType } from '@ngx-formly/core';
@Component({
selector: 'app-formly-datepicker',
templateUrl: './formly-datepicker.component.html',
styleUrls: ['./formly-datepicker.component.scss']
})
export class FormlyDatepickerComponent extends FieldType{
inputDateToField(event: NgbDate){
this.model.session_date = `${event.year}-${event.month}-${event.day}`;
}
}
我试过在 ngOnInit() 和 ngAfterViewInit() 中操作模型,我试过设置 startDate,但在这种情况下似乎没有任何帮助。我在这里做什么?
我强烈建议您更新 NgBootstrap 和 Formly 的配置(如果您还没有更新的话):
- 不要在组件中使用
inputDateToField
方法,而是创建 NgBootstrap 为 NgbDatePicker 推荐的 two services (parser and adapter) 方法。解析器将维护您在model
中指定的格式,适配器将再次根据您的自定义显示 UI 中的日期。例如。我使用解析器转换后端提供的 ISO 字符串,以便在我的model
中将其保存为 'YYYY-MM-DD',并使用适配器将其显示为 'DD-MM-YYYY' - 无论你在哪里导入
FormlyModule
像这样更新配置(如果它不在 AppModule 中,你可能必须使用forChild
):
FormlyModule.forRoot({types: [{ name: 'date', component: FormlyDatepickerComponent, extends: 'input'}]})
- 在您的
FormlyDatepickerComponent
模板中,添加type="text"
(可选)。
你可以采取两种方法:
1.-创建表单时使用 NgbDateStruct 作为默认值
//I imagine you has an object "data" with a property "date"
//in the way yyyy-mm-dd and create the field as
{
key: 'date',
type: 'input',
defaultValue: {
year:+data.date.substr(0,4),
month:+data.date.substr(5,2),
day:+data.date.substr(8,2)
},
templateOptions: {
label: 'First Name (initialized via default value)',
},
},
在这种情况下,您总是管理“日期”一个具有属性年月日的对象,是的,FormControl 可以存储一个对象,它不是“extrange”
2.- 使用管理字符串的自定义适配器。这有点复杂。您需要创建两个 class:
CustomAdepter
@Injectable()
export class CustomAdapter extends NgbDateAdapter<string> {
readonly DELIMITER = '-';
fromModel(value: string | null): NgbDateStruct | null {
if (value) {
let date = value.split(this.DELIMITER);
return {
day : parseInt(date[2], 10),
month : parseInt(date[1], 10),
year : parseInt(date[0], 10)
};
}
return null;
}
toModel(date: NgbDateStruct | null): string | null {
return date ? date.year+ this.DELIMITER+('00'+date.month).slice(-2) + this.DELIMITER + ('00'+date.day).slice(-2) : null;
}
}
和 CustomDateParserFormatter(当您输入时创建 ngbDateStructurt)
@Injectable()
export class CustomDateParserFormatter extends NgbDateParserFormatter {
readonly DELIMITER = '-';
parse(value: string): NgbDateStruct | null {
if (value) {
const separator=value.indexOf(".")>=0?".":value.indexOf("-")>=0?"-":value.indexOf("/")>=0?"/":null
if (separator)
{
let date = value.split(separator);
return {
day : parseInt(date[2], 10),
month : parseInt(date[1], 10),
year : parseInt(date[0], 10)
};
}
}
return null;
}
format(date: NgbDateStruct | null): string {
return date ? date.year+ this.DELIMITER+('00'+date.month).slice(-2) + this.DELIMITER + ('00'+date.day).slice(-2) : "";
}
}
然后在你的组件中你需要在你的模块中添加作为提供者(你也可以在你的组件中添加作为提供者)
providers: [
{provide: NgbDateAdapter, useClass: CustomAdapter},
{provide: NgbDateParserFormatter, useClass: CustomDateParserFormatter}
]
现在您可以使用,您的模型或 formControl 将是一个字符串
一个forked stackblitz the example in ng-bootstrap