39 votes

knockoutjs databind avec jquery-ui datepicker

J'utilise un jQuery UI datepicker. Le champ de saisie HTML qui se trouve derrière est actuellement relié à KnockoutJS en tant que dependentObservable, mais lorsque sa valeur est définie dans le viewmodel, le sélecteur de date perd son format.

Comment dois-je procéder sans perdre le format ? J'aimerais que le viewModel ne sache pas qu'il s'agit d'un fichier de type jQuery datepicker.

80voto

RP Niemeyer Points 81663

Vous pourriez écrire une liaison personnalisée qui définit la date dans le champ à l'aide des API de sélecteur de date et qui définit également la valeur de votre observable en lisant correctement la date.

La reliure personnalisée pourrait ressembler à ceci :

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

        //initialize datepicker with some optional options
        $el.datepicker(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", 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),
            current = $el.datepicker("getDate");

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

Vous l'utiliseriez comme :

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

El datepickeroptions est facultatif et peut inclure tout ce que vous voulez passer dans l'option datepicker() appeler.

En outre, cela suppose que vous utilisez un observable pour la date. La liaison doit faire un peu plus de travail si vous voulez faire une liaison à sens unique avec une non-observable, mais c'est peu probable.

Un échantillon ici : http://jsfiddle.net/rniemeyer/NAgNV/

6voto

Evan Larsen Points 4352

J'ai utilisé le code de RP Niemeyer marqué comme la réponse ci-dessus, mais depuis que je l'utilise, j'y ai apporté quelques petites modifications. Je me suis dit que j'allais les poster ici. Peut-être que cela aidera d'autres personnes. C'est à peu près la même chose, la seule différence est que si l'élément a une valeur au moment du chargement de la page, il conservera cette valeur. De plus, j'ai fait $elem une variable afin qu'il y ait moins de traitement de $(element) que jQuery devra faire.

ko.bindingHandlers['jqDatePicker'] = {
    'init': function(element, valueAccessor, allBindingsAccessor) {
        /* Initialize datepicker with some optional options */
        var options = allBindingsAccessor().jqDatePickerOptions || {},
            prop = valueAccessor(),
            $elem = $(element);

        prop($elem.val());

        $elem.datepicker(options);

        /* Handle the field changing */
        ko.utils.registerEventHandler(element, "change", function () {
            prop($elem.datepicker("getDate"));
        });

        /* Handle disposal (if KO removes by the template binding) */
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $elem.datepicker("destroy");
        });
    },
    'update': function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor()),
            $elem = $(element),
            current = $elem.datepicker("getDate");

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

6voto

OddEssay Points 617

J'ai dû faire une légère modification pour que le code de RP Niemeyer fonctionne dans mon code en utilisant l'option dateFormat, en remplaçant

$(element).datepicker("getDate")

Avec

$(element).val()

La version formatée de la date a donc été transmise correctement sous le capot.

2voto

viggity Points 5342

Voici ce qui a fonctionné dans mon cas particulier. J'utilise une version suffisamment récente de MVC pour que le sérialiseur de date par défaut soit rendu à la norme ISO 8601 (cf. Sur le cauchemar que sont les dates JSON. Plus, JSON.NET et ASP.NET Web API ). Mes fixations ne pas écrire directement dans le sélecteur de date, mais plutôt dans l'attribut "value" d'une balise de saisie.

En outre, j'utilise date.js

ko.bindingHandlers.dateValue = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor(),
            allBindings = allBindingsAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
        var pattern = allBindings.datePattern || 'MM/dd/yyyy';
        var date = Date.parse(valueUnwrapped)
        $(element).val(date.toString(pattern));
    },

    init: function(element, valueAccessor, allBindingsAccessor) {
        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            var date = Date.parse($(element).val());
            observable(date.toString("yyyy-MM-ddThh:mm:ss"));
        });
    }
}

La fixation ressemble à ceci :

<input class="date" type="text" data-bind="dateValue: SomeViewModelDate" />

Et le code JavaScript pour activer le sélecteur de date :

$(document).ready(function () {
    $('.date').datepicker({ dateFormat: "mm/dd/yy" });
});

1voto

Russellg Points 83

Les exemples de sélecteur de date ci-dessus modifient le format de la date dans le modèle de vue, qui passe de WCF au format de date JavaScript lorsque l'utilisateur sélectionne une nouvelle date dans le contrôle du sélecteur de date.

Dans mon cas, je renvoyais la date à un service WCF, et il n'acceptait pas une date JavaScript désérialisée, il avait besoin de la date au format WCF. J'ai modifié le script ci-dessus pour qu'il stocke la date dans le viewmodel au format WCF afin qu'elle puisse être renvoyée au serveur dans ce format.

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).datepicker("getDate"));
            // store the date in 'WCF String format"
            var tempdate=$(element).datepicker("getDate");
            var tempdatestr="/Date("+tempdate.getTime()+")/";
            observable(tempdatestr);
        });
        //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());
        //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);
        }
    }
};

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