web-dev-qa-db-fra.com

Bootstrap datepicker avec knockout.js databind

Cette question est similaire à knockoutjs databind avec jquery-ui datepicker , mais au lieu du jQueryUI datepicker, je voudrais utiliser l'un des Bootstrap datepickers .

L'API pour le sélecteur de date Bootstrap est différente de jquery-ui, et j'ai du mal à comprendre comment le faire fonctionner avec knockout.js. J'ai créé n jsFiddle pour l'essayer .

Il semble que le sélecteur de date Bootstrap pourrait être beaucoup plus simple à utiliser car il ne stocke pas la date de manière indépendante. Cependant, je voudrais savoir si le jsFiddle est le moyen approprié d'utiliser le widget de datepicker Bootstrap avec knockout.js, c'est-à-dire.

ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor) {
      //initialize datepicker with some optional options
      var options = allBindingsAccessor().datepickerOptions || {};
      $(element).datepicker(options);

      ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).datepicker("destroy");
        });
    },
    update: function(element, valueAccessor) {
    }
};
22
Brian M. Hunt

Voici un exemple de la façon dont vous pouvez accomplir cela avec le sélecteur de dates que vous utilisez:

ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor) {
      //initialize datepicker with some optional options
      var options = allBindingsAccessor().datepickerOptions || {};
      $(element).datepicker(options);

      //when a user changes the date, update the view model
      ko.utils.registerEventHandler(element, "changeDate", function(event) {
             var value = valueAccessor();
             if (ko.isObservable(value)) {
                 value(event.date);
             }                
      });
    },
    update: function(element, valueAccessor)   {
        var widget = $(element).data("datepicker");
         //when the view model is updated, update the widget
        if (widget) {
            widget.date = ko.utils.unwrapObservable(valueAccessor());
            if (widget.date) {
                widget.setValue();            
            }
        }
    }
};

Il ne semblait pas y avoir de fonctionnalité de destruction, j'ai donc supprimé cette pièce. Cela gère l'événement widgets changeDate pour mettre à jour le modèle de vue, lorsqu'un utilisateur modifie la date. La fonction update gère lorsque le modèle de vue est modifié pour mettre à jour le widget.

Si vous voulez lier la valeur à un élément non observable, cela prendrait un peu plus de code. Faites-moi savoir si c'est quelque chose que vous devez soutenir.

http://jsfiddle.net/rniemeyer/KLpq7/

41
RP Niemeyer

ma version actuelle est un mélange entre les solutions déjà montrées:

ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {

    var unwrap = ko.utils.unwrapObservable;
    var dataSource = valueAccessor();
    var binding = allBindingsAccessor();

    //initialize datepicker with some optional options
    var options = allBindingsAccessor().datepickerOptions || {};
    $(element).datepicker(options);
    $(element).datepicker('update', dataSource());
    //when a user changes the date, update the view model
    ko.utils.registerEventHandler(element, "changeDate", function (event) {
        var value = valueAccessor();
        if (ko.isObservable(value)) {
            value(event.date);
        }
    });
},
update: function (element, valueAccessor) {
    var widget = $(element).data("datepicker");

    var value = ko.utils.unwrapObservable(valueAccessor());

    //when the view model is updated, update the widget
    if (widget) {
        widget.date = value;
        if (widget.date) {
            widget.setValue();
            $(element).datepicker('update', value)
        }
    }
}};
6
Philipp P

La réponse acceptée ne fonctionnait pas pour moi avec la version actuelle du sélecteur de date. L'entrée n'était pas initialisée avec la valeur de l'observable. J'ai fait une liaison mise à jour, à laquelle j'ai ajouté ceci:

$(element).datepicker('update', dataSource());

Cela semble faire l'affaire.

Voici un violon mis à jour qui utilise le dernier sélecteur de date disponible, Bootstrap, jQuery et Knockout: http://jsfiddle.net/krainey/nxhqerxg/

Mise à jour:

J'ai rencontré des difficultés avec le sélecteur de date qui ne jouait pas bien avec l'observable lorsqu'un utilisateur modifiait manuellement la valeur dans le champ de texte. L'outil analysait immédiatement la date et connectait le résultat au champ de saisie.

Si l'utilisateur tentait de modifier le 10/07/2014, par exemple, et utilisait le retour arrière ou la suppression pour supprimer un nombre (10/0/2014), la valeur résultante serait analysée immédiatement et insérée dans la saisie de texte. Si la valeur était, pendant un moment, 10/0/2014, le sélecteur déplacerait le calendrier au 30/09/2014 et brancherait cette valeur dans le champ de texte. Si j'essayais de modifier le mois, et que la valeur était, pendant un moment, le 1/7/2014, le sélecteur se déplaçait au 7 janvier 2014 et connectait cette valeur au champ de texte.

Vous pouvez voir ce comportement dans ce violon:

http://jsfiddle.net/krainey/nxhqerxg/10/

J'ai dû mettre à jour ma liaison avec un gestionnaire spécial pour détecter le focus et lier un événement de flou unique pour qu'il gère correctement les modifications manuelles.

$(element).on("changeDate", function (ev) {
    var observable = valueAccessor();
    if ($(element).is(':focus')) {
        // Don't update while the user is in the field...
        // Instead, handle focus loss
        $(element).one('blur', function(ev){
            var dateVal = $(element).datepicker("getDate");
            observable(dateVal);
        });
    }
    else {
        observable(ev.date);
    }
});

Le violon référencé dans la réponse originale a été mis à jour pour refléter ceci:

http://jsfiddle.net/krainey/nxhqerxg/

5
kiprainey

Voici ce que j'ai fini

ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
    //initialize datepicker with some optional options

    var options = {
        autoclose: true,
        format: 'yyyy-mm-dd',
    }

    //var options = allBindingsAccessor().datepickerOptions || {};
    $(element).datepicker(options);

    //when a user changes the date, update the view model
    ko.utils.registerEventHandler(element, "changeDate", function (event) {
        var value = valueAccessor();

        if (ko.isObservable(value)) {
            var myDate = event.date;
            var month = myDate.getMonth() + 1;
            var monthText = month;

            if (month < 10)
                monthText = "0" + month;

            var day1 = parseInt(myDate.getDate());
            var dayText = day1;

            if (day1 < 10)
                dayText = '0' + day1;

            value(myDate.getFullYear() + '-' + monthText + '-' + dayText);
        }
    });
},
update: function (element, valueAccessor) {

    var widget = $(element).data("datepicker");
    //when the view model is updated, update the widget
    if (widget) {
        widget.date = ko.utils.unwrapObservable(valueAccessor());
        widget.setValue(widget.date);
    }
}};
2
Muhammad Amin