【问题标题】:NgbDatepicker in Reactive Forms with formly: Set Initial Value反应形式中的 NgbDatepicker 与 formly:设置初始值
【发布时间】:2021-03-08 19:07:33
【问题描述】:

我正在尝试以角度反应形式使用 ngbDatepicker,并且希望能够显示初始值。

我的问题是very similar to another one 有一个关键的区别,我也在使用formly,这是一个用于自动生成表单的角度包。由于原始问题的答案是基于生成一个新的 formControl 并将其添加到表单中,在我的情况下,这是由 formly 完成的,这就是我努力的原因。

“组件”通常在您要输入新值时起作用(因为这会触发我用来更改模型值的事件),但初始值未正确显示。虽然模型始终具有例如的值“2020-07-05”如果使用占卜检查,则永远不会显示在输入字段中。如果我将模型中的日期转换为 ngOnInit() 中的 NgbDate ({year, month, day}),这仍然是正确的。

Formly 调用我的自定义组件(定义如下),该组件仅包含字段并将预先存在的表单控件(包括模型)和字段配置绑定到输入字段。 The component itself doesn't do much, it contains the necessary HTML for the ngbDatepicker and a function that, when a date is chosen, converts it from an NgbDate ({year, month, day}) to a string ("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,但在这种情况下似乎没有任何帮助。我在这里做什么?

【问题讨论】:

  • 您能找到解决方案吗?即使我面临完全相同的问题。当自定义模板是一个简单的文本框时它可以工作,但当我将它更新为 ngbDatepicker
  • @Aashwath Acharya 遗憾的是没有。我通常会用我找到的解决方案的详细解释来更新我的问题,但是直到今天我都没有找到这个。
  • 它实际上对我有用,我以不正确的格式而不是 YYYY-MM-DD 传递了日期。不同之处可能在于 NgBootstrap 和 Formly 库的配置。已在我的回答中详细说明。

标签: angular datepicker angular-reactive-forms ng-bootstrap angular-formly


【解决方案1】:

我会敦促您更新 NgBootstrap 和 Formly 的配置(如果您还没有):

  1. 不要在组件中使用inputDateToField 方法,而是为 NgBootstrap 为 NgbDatePicker 创建这些 two services (parser and adapter)。解析器将保持您在 model 中指定的格式,并且适配器将再次根据您的自定义在 UI 中显示日期。例如。我使用解析器转换后端提供的 ISO 字符串以将其保存为 model 中的“YYYY-MM-DD”,并使用适配器将其显示为“DD-MM-YYYY”
  2. 无论你在哪里导入FormlyModule,都要像这样更新配置(如果它不在AppModule中,你可能必须使用forChild):
FormlyModule.forRoot({types: [{ name: 'date', component: FormlyDatepickerComponent, extends: 'input'}]})
  1. FormlyDatepickerComponent 的模板中,添加type="text"(可选)。

【讨论】:

  • 实际上不需要“扩展:输入”位。对于我的特定问题,实现CustomAdapterCustomDateParserFormatter 足以解决问题。
  • @PhilippDoerner 忘了提到它是可选的。 extends 属性将自动执行其他字段选项,例如标签、验证错误消息等。否则,您必须在组件中明确包含它们的代码
【解决方案2】:

你可以采取两种方法:

1.-创建表单时使用NgbDateStruct作为defaultValue

//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 可以存储一个对象,它不是“外部”

2.- 使用管理字符串的自定义适配器。这有点复杂。你需要创建两个类:

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 stackblitzng-bootstrap 中的示例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 2020-04-03
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    • 2019-09-21
    • 1970-01-01
    相关资源
    最近更新 更多