web-dev-qa-db-fra.com

Comment détecter bootstrap datetimepicker changer les événements dans angular2

J'utilise le bootstrap datetimepicker in angular 2

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

Dans mon modèle, j'ai:

<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>

Le problème est que lorsque je sélectionne une date sur le calendrier par clic, il ne déclenche aucun événement "change" (en d'autres termes, ngModel n'est pas déclenché). Si je tape dans la zone de texte, le {{date}} me montre la valeur plus le texte que j'ai tapé.

Comment puis-je détecter des modifications dans la zone de texte si l'utilisateur clique sur une date dans le sélecteur pour la modifier?

15
Sireini

Le problème est que Angular ne sait pas que la valeur de l'entrée a changé afin de mettre à jour ngModel. Une autre chose étrange est que bootstrap-datetimepicker ne déclenche pas l'événement de changement sur l'entrée - ceci nécessite une solution de contournement.

Voir cet exemple de travail:

<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>

Remarquez les changements:

  • [ngModel]="date": nous avons seulement besoin d'une liaison de données à sens unique (du modèle à la vue) car Angular ne sait pas quand la valeur de l'entrée a changé
  • #datePicker: J'ai créé une variable locale afin d'accéder à sa valeur
  • (blur)="date = datePicker.value": sur flou on met à jour le modèle
15
Cosmin Ababei

Le problème, comme indiqué par les autres réponses, est que ngModel ne détecte pas la modification effectuée par la bibliothèque tierce. ngModel utilise une liaison de données bidirectionnelle. Essentiellement, quand vous dites

<div [(ngModel)]="date">

cela équivaut à

<div [ngModel]="date" (ngModelChange)="date=$event">.

J'ai créé une directive pour émettre l'événement ngModelChange, comme suit:

@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();
    };
};
7
Joe aka user3169887

La solution publiée par user3169887 a très bien fonctionné jusqu'à ce que je passe d'un formulaire basé sur un modèle (utilise ngModel) à un formulaire réactif.

En approfondissant le problème d'origine, j'ai appris que Angular écoute l'événement "input" que ces bibliothèques de datepicker ne déclenchent pas. Ma solution a été de modifier la directive pour déclencher "l'entrée" plutôt que d'émettre l'événement ngModelChange. J'ai testé cette directive avec un formulaire piloté par modèle et un formulaire réactif et les deux semblaient fonctionner.

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");
    };
};

Notez que j'utilise une bibliothèque de datepicker différente, donc j'écoute l'événement "changeDate" et votre bibliothèque peut déclencher un événement différent comme "dp.change".

5
jaggedaz

Essayez ngModelChange au lieu de change.

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

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

Je ne sais pas si cela fonctionne, mais selon les documents, le bon événement à écouter est change

<div class='input-group date datepicker' (change)="date=$event">
1
Günter Zöchbauer