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

时间:2018-03-20 19:50:59

标签: angular ng-bootstrap

我正在尝试用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已导入每个模块(应用模块中为ngbModule.forRoot()),FormsModule始终在NgbModule之前导入。

Angular版本5.2.3
ng-bootstrap版本1.02

感谢任何帮助。

Plunker

1 个答案:

答案 0 :(得分:2)

您需要在DatePickerPopupComponent上实现ControlValueAccessor。这将允许角形式(模板或反应)模型与组件绑定。你的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);
  }
}