Angular 5 模型绑定不适用于 ng-bootstrap 日期选择器弹出窗口

Angular 5 model binding not working for ng-bootstrap date picker popup

我正在尝试使用 ng-bootstrap 的日期选择器弹出窗口制作我自己的组件(我不想每次使用日期选择器时都需要所有这些标记)。

日期选择器自己运行良好,但该值未绑定回使用该组件的页面。

这是我的日期选择器 - 从 ng-bootstrap 的示例页面复制:

<div class="input-group">
  <input class="form-control" placeholder="yyyy-mm-dd" name="dp"  [(ngModel)]="selectedDate" ngbDatepicker #d="ngbDatepicker">
  <div class="input-group-append">
    <button class="btn btn-outline-secondary" (click)="d.toggle()" type="button">
      <img src="img/calendar-icon.svg" style="width: 1.2rem; height: 1rem; cursor: pointer;"/>
    </button>
  </div>
</div>

<hr/>
<pre>Model: {{ selectedDate | json }}</pre>

我的组件:

import { Component, OnInit } from '@angular/core';
import {NgbDateStruct, NgbDateParserFormatter} from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'reo-datepicker-popup',
  templateUrl: './datepicker-popup.component.html',
})
export class DatepickerPopupComponent implements OnInit {

  selectedDate; any;

  constructor() {}

  ngOnInit() {
  }

}

组件是这样使用的:

<reo-datepicker-popup  [(ngModel)]="selectedDatePopup"  ngDefaultControl name="datePicker"></reo-datepicker-popup>

我的页面上还有其他控件 [(ngModel)] 按预期工作。我可以在父页面中为 selectedDatePopup 设置默认值 - 该值将向下传播到日期选择器,但在更改时不会返回到父页面。

我试过 @Input() 而不是 [(ngModel)],结果相同。我还验证了每个模块中都导入了 NgbModule(app 模块中的 ngbModule.forRoot()),并且 FormsModule 总是在 NgbModule.

之前导入

Angular 版本 5.2.3
ng-bootstrap 版本 1.02

感谢任何帮助。

Plunker

您需要在 DatePickerPopupComponent 上实现 ControlValueAccessor。这将允许 angular 表单(模板或反应式)与您的组件进行模型绑定。你的 plnkr 不再工作了。我在 StackBlitz 上创建了一个示例。我必须添加一些额外的代码来翻译 ngbDatePicker 的日期。可能有更好的方法来做到这一点。这应该足以让您朝着正确的方向前进。

组件代码应该是这样的:

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

export const DATEPICKER_VALUE_ACCESSOR =  {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => DatePickerComponent),
  multi: true
};

@Component({
  selector: 'app-date-picker',
  templateUrl: './date-picker.component.html',
  providers: [DATEPICKER_VALUE_ACCESSOR]
})
export class DatePickerComponent implements ControlValueAccessor {

  selectedDate: any;
  disabled = false;

  // Function to call when the date changes.
  onChange = (date?: Date) => {};

  // Function to call when the date picker is touched
  onTouched = () => {};

  writeValue(value: Date) {
    if (!value) return;
    this.selectedDate = {
      year: value.getFullYear(),
      month: value.getMonth(),
      day: value.getDate()
    }
  }

  registerOnChange(fn: (date: Date) => void): void {
    this.onChange = fn;
  }

  // Allows Angular to register a function to call when the input has been touched.
  // Save the function as a property to call later here.
  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  // Allows Angular to disable the input.
  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  // Write change back to parent
  onDateChange(value: Date) {
    this.onChange(value);
  }

  // Write change back to parent
  onDateSelect(value: any) {
    this.onChange(new Date(value.year, value.month - 1, value.day));
  }

}

标记:

<form class="form-inline">
  <div class="form-group">
    <div class="input-group">
      <input class="form-control" 
             placeholder="yyyy-mm-dd"
             name="dp" 
             [(ngModel)]="selectedDate"
             ngbDatepicker #d="ngbDatepicker"
             (change)="onDateChange($event.target.value)"
             (dateSelect)="onDateSelect($event)">

      <div class="input-group-append">
        <button class="btn btn-outline-secondary" (click)="d.toggle()" type="button">
          [[]]
        </button>
      </div>
    </div>
  </div>
</form>

<hr/>
<pre>Model on date picker: {{ selectedDate | json }}</pre>

组件上的实现:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1>
  <div>
    This is the date picker: <app-date-picker [(ngModel)]="selectedDate"></app-date-picker>
  </div>
  <div>
    Model on parent: {{ selectedDate | date:'short' }}
  </div>
  `,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  @Input() name: string;
  public selectedDate: Date;
  constructor() {
    this.selectedDate = new Date(2018, 1, 1);
  }
}