134 votes

Événement de changement de datepicker de l'interface utilisateur jQuery non intercepté par KnockoutJS

Je suis en train d'utiliser KnockoutJS avec jQuery UI. J'ai un élément d'entrée avec un datepicker ci-joint. Je suis actuellement en cours d'exécution knockout.debug.1.2.1.js , et il semble que le changement de l'événement est de ne jamais être pris par knock-out. L'élément ressemble à ceci:

<input type="text" class="date" data-bind="value: RedemptionExpiration"/>

J'ai même essayé de changer l' valueUpdate type d'événement, mais en vain. Il semble que Chrome provoque une focus événement juste avant le changement de valeur, mais IE n'est pas.

Est-il un knock-out méthode qui "relie toutes les liaisons"? J'techniquement seulement besoin de la valeur a changé avant de me l'envoyer vers le serveur. Donc, je pourrais vivre avec ce genre de solution de contournement.

Je pense que le problème est le datepicker de la faute, mais je ne peux pas comprendre comment résoudre ce problème.

Des idées?

253voto

RP Niemeyer Points 81663

Je pense que pour le jQuery UI datepicker il est préférable d'utiliser une liaison personnalisée qui sera en lecture/écriture avec Date d'objets à l'aide de l'Api fournies par le datepicker.

La liaison pourrait ressembler (à partir de ma réponse ici):

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

        $el.datepicker(options);

        //handle the field changing by registering datepicker's changeDate event
        ko.utils.registerEventHandler(element, "changeDate", function () {
            var observable = valueAccessor();
            observable($el.datepicker("getDate"));
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $el.datepicker("destroy");
        });

    },
    update: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor()),
            $el = $(element);

        //handle date data coming via json from Microsoft
        if (String(value).indexOf('/Date(') == 0) {
            value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1")));
        }

        var current = $el.datepicker("getDate");

        if (value - current !== 0) {
            $el.datepicker("setDate", value);
        }
    }
};

Vous pouvez l'utiliser comme:

<input data-bind="datepicker: myDate, datepickerOptions: { minDate: new Date() }" />

Exemple dans jsFiddle ici: http://jsfiddle.net/rniemeyer/NAgNV/

13voto

Brad M Points 327

Voici une version de RP Niemeyer réponse qui va travailler avec le knock-out de validation des scripts trouvés ici: http://github.com/ericmbarnard/Knockout-Validation

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

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            observable($(element).val());
            if (observable.isValid()) {
                observable($(element).datepicker("getDate"));

                $(element).blur();
            }
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).datepicker("destroy");
        });

        ko.bindingHandlers.validationCore.init(element, valueAccessor, allBindingsAccessor);

    },
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());

        //handle date data coming via json from Microsoft
        if (String(value).indexOf('/Date(') == 0) {
            value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1")));
        }

        current = $(element).datepicker("getDate");

        if (value - current !== 0) {
            $(element).datepicker("setDate", value);
        }
    }
};

Les changements sont pour le changement de gestionnaire d'événement pour passer la valeur entrée et non à la date de la validation des scripts d'abord, puis seulement réglage de la date pour l'observable si elle est valide. J'ai aussi ajouté le validationCore.init qui est nécessaire pour les liaisons personnalisées discuté ici:

http://github.com/ericmbarnard/Knockout-Validation/issues/69

J'ai également ajouté rpenrose suggestion pour un flou sur le changement d'éliminer certains satanés datepicker scénarios de choses.

11voto

ThiagoPXP Points 545

J'ai utilisé une approche différente. Comme knockout.js ne semble pas déclencher l'événement lors d'un changement, j'ai forcé le coupleur de date à appeler change () pour sa saisie une fois fermée.

 $(".date").datepicker({
    onClose: function() {
        $(this).change(); // Forces re-validation
    }
});
 

9voto

brudert Points 187

Bien que toutes ces réponses m'a sauvé beaucoup de travail, aucun d'entre eux entièrement travaillé pour moi. Après sélection d'une date, le bindings valeur ne serait pas de mise à jour. Je n'ai pu avoir à mettre à jour lors de la modification de la valeur de la date à l'aide du clavier puis en cliquant hors de la zone de saisie. J'ai corrigé cela en augmentant RP Niemeyer code avec syb du code pour obtenir:

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

            var funcOnSelectdate = function () {
                var observable = valueAccessor();
                observable($(element).datepicker("getDate"));
            }

            options.onSelect = funcOnSelectdate;

            $(element).datepicker(options);

            //handle the field changing
            ko.utils.registerEventHandler(element, "change", funcOnSelectdate);

            //handle disposal (if KO removes by the template binding)
            ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                $(element).datepicker("destroy");
            });

        },
        update: function (element, valueAccessor) {

            var value = ko.utils.unwrapObservable(valueAccessor());
            if (typeof(value) === "string") { // JSON string from server
                value = value.split("T")[0]; // Removes time
            }

            var current = $(element).datepicker("getDate");

            if (value - current !== 0) {
                var parsedDate = $.datepicker.parseDate('yy-mm-dd', value);
                $(element).datepicker("setDate", parsedDate);
            }
        }
    };

Je le soupçonne de mettre le observables($(element).datepicker("getDate")); déclaration dans sa propre fonction et de l'enregistrement avec des options.onSelect a fait le tour?

6voto

rpenrose Points 61

Merci pour cet article, je l'ai trouvé très utile.

Si vous souhaitez que le composant DatePicker se comporte exactement comme le comportement par défaut de l'interface utilisateur JQuery, je vous recommande d'ajouter un flou sur l'élément dans le gestionnaire d'événements change:

c'est à dire

     //handle the field changing
    ko.utils.registerEventHandler(element, "change", function () {
        var observable = valueAccessor();
        observable($(element).datepicker("getDate"));

        $(element).blur();

    });
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X