如何在Angular2中检测Bootstrap datetimepicker的变化事件

20

我正在Angular 2中使用Bootstrap日期时间选择器。

https://eonasdan.github.io/bootstrap-datetimepicker/

在我的模板中,我有:

<div class='input-group date datepicker'>
         <input type='text' class="form-control" [(ngModel)]="date">
         <span class="input-group-addon">
         <span class="glyphicon glyphicon-calendar" (click)="getCalendar()"></span>
       </span>
   {{date}}
</div>

问题在于当我通过点击日历选择日期时,它不触发任何“更改”事件(换句话说,ngModel未激活)。如果我在文本框中键入,则{{date}}会显示我键入的值和文本。

如果用户点击选择器更改日期,我如何检测文本框中的更改?


1
也许你可以使用 ng2-bootstrap 的日期选择器? - Thierry Templier
5个回答

23

使用 ngModelChange 而不是 change

<input class="form-control" (ngModelChange)="changeDate($event)"
      [(ngModel)]="startRegistrationDate" ngbDatepicker #start="ngbDatepicker">

// to catch the event
changeDate(event: any) {
  console.log(event);
}

只有在使用ngmodel时才能工作,不能与响应式表单一起使用。 - Solid_Metal
1
@Solid_Metal,您现在可以使用“[ngModelOptions] =”{standalone: true}“来解决这个问题。 - Azoulay Jason

20

问题在于Angular不知道输入框的值已经改变了,因此无法更新ngModel。另一个奇怪的事情是,bootstrap-datetimepicker不会触发输入框的change事件 - 这需要一些解决方法。

查看这个可行的例子:


<div class='input-group date datepicker'>
  <input type='text' class="form-control" #datePicker [ngModel]="date" (blur)="date = datePicker.value">
  <span class="input-group-addon">
    <span class="glyphicon glyphicon-calendar" (click)="getCalendar()"></span>
  </span>

  {{date}}
</div>

注意以下更改:

  • [ngModel]="date": 我们仅需要单向数据绑定(从模型到视图),因为Angular不知道输入的值何时发生变化
  • #datePicker: 我创建了一个局部变量以便访问它的值
  • (blur)="date = datePicker.value": 在失焦时我们更新模型

打算去看一下,刚刚看到了你的回答 :) - Sireini
@初学者编程 我很高兴它对你有帮助。这不是完美的解决方案,因为模型只在输入变模糊时更新。 - Cosmin Ababei
<select class="form-control" [(ngModel)]="expression.constraint"> <option *ngFor="#constraint of prototype.constraints" [value]="constraint"> {{ constraint }} </option> </select> - Sireini
如果我使用console.log(expression),它会显示一个带有选定选项的对象。 - Sireini
我的问题是如何将它绑定到上述那个表达式对象? - Sireini
显示剩余3条评论

7
其他答案中所述的问题是ngModel没有捕捉到第三方库所做的更改。ngModel使用双向数据绑定。基本上,当您说
那相当于

我的做法是创建一个指令来发出ngModelChange事件,如下所示:
@Directive({
    selector: [datepicker],
    outputs: [
        "ngModelChange"
    ]
})
export class DatePickerDirective {
    //Emits changes to ngModel
    ngModelChange = new EventEmitter();
    el: JQuery;

    //Obtains the handle to the jQuery element
    constructor(el){
        this.el = jQuery(el.nativeElement);
    }

    ngOnInit() {
        this.el.datetimepicker({
            //Initialization options
        });

        this.el.on('dp.change', (event) => {
            var moment: Moment = event.date;

            //Emit new value
            this.ngModelChange.emit(date.format(/*However you want it formatted*/));
        });
    };

    ngOnDestroy() {
        //Clean up
        this.el.data('DateTimePicker').destroy();
    };
};

1
ElementRef没有"on"。它可能在rc5或之后被删除了。现在应该是this.el.nativeElement.onchange= function(event) { }吗?https://angular.io/docs/js/latest/api/core/index/ElementRef-class.html - Stephen
应该改为 this.el.nativeElement.onchange= (event) => { },这样可以解决 this 的问题。 - Stephen
很好知道。将this.el更改为JQuery类型(需要JQuery typings才能这样做,除非你足够大胆使用“any”),这是对this.el更好的表示方式。 - Joe aka user3169887
(ngModelChange) 而不是 (change) 正是我所需要的。 - Ron Newcomb

5

用户3169887发布的解决方案对我非常有用,但是当我从模板驱动表单(使用ngModel)切换到响应式表单时出现了问题。

深入研究原始问题后,我发现Angular正在监听“input”事件,而这些日期选择器库不会触发该事件。我的解决方案是调整指令以触发“input”事件,而不是发出ngModelChange事件。我测试了这个指令,包括模板驱动表单和响应式表单,两者都似乎可以正常工作。

import { Directive, ElementRef, Renderer, Input, OnInit } from "@angular/core";

declare var $: any;

@Directive({
    selector: "[datepicker]"
})
export class DatePickerDirective implements OnInit {
    @Input("datepicker")
    private datepickerOptions: any = {};
    private $el: any;

    constructor(private el: ElementRef, private renderer: Renderer) {
        this.$el = $(el.nativeElement);
    }

    ngOnInit() {
        // Initialize the date picker
        this.$el.datepicker(this.datepickerOptions)
            // Angular is watching for the "input" event which is not fired when choosing
            // a date within the datepicker, so watch for the "changeDate" event and manually
            // fire the "input" event so that Angular picks up the change
            // See: angular/modules/@angular/forms/src/directives/default_value_accessor.ts
            .on("changeDate", (event) => {
                let inputEvent = new Event("input", { bubbles: true });
                this.renderer.invokeElementMethod(this.el.nativeElement, "dispatchEvent", [inputEvent]);
            });
    };

    ngOnDestroy() {
        this.$el.datepicker("destroy");
    };
};

请注意,我正在使用不同的日期选择库,因此我正在监听“changeDate”事件,而您的库可能会触发不同的事件,如“dp.change”。

工作得很好,正在为UI日期选择器进行调整,使用“onSelect”。 - Robin Schaaf
看起来不错...我要试一下这个。 - Muhammad Arslan

0

不确定这是否有效,但根据文档,要监听的正确事件是change

<div class='input-group date datepicker' (change)="date=$event">

<div class='input-group date datepicker' (change)="date=$value"> <input type='text' class="form-control" [(ngModel)]="date"> {{date}} </div> 像这样是不工作的。 - Sireini
请尝试使用<div class='input-group date datepicker' (change)="handleChange($value)">并添加handleChange($event) { console.log(event); }。我之前的回答有误 - 已更新。(将$value更改为$event) - Günter Zöchbauer
2
问题在于Bootstrap DateTimePicker不会触发输入框的change事件。实际上,它有一个自定义事件"dp.change",但是Angular似乎无法在(dp.change)中捕获它。 - Cosmin Ababei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接