knockoutjs databind avec jQuery-ui datepicker

j'utilise un jQuery UI datepicker. Le champ D'entrée HTML derrière lui est actuellement accroché à KnockoutJS en tant qu'observable fiable, mais lorsque sa valeur est définie dans le viewmodel, le curseur de données perd son format.

Comment faire et ne pas perdre le format? Je voudrais que le viewModel ne sache pas qu'il s'agit d'un jQuery datepicker.

38
demandé sur Peter Mortensen 2011-06-19 01:47:17

7 réponses

vous pouvez écrire une liaison personnalisée qui fixe la date dans le champ à l'aide du curseur de données APIs et définit également la valeur de votre observable en lisant la date correctement.

La liaison personnalisée pourrait ressembler à:

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'utilisez comme:

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

le datepickeroptions serait facultatif et pourrait inclure tout ce que vous voulez passer dans l'appel datepicker() .

aussi, cela suppose que vous utilisez un observables pour la date. La liaison doit faire un peu plus si vous voulez faire une liaison avec un non-observables, mais c'est peu probable.

exemple ici: http://jsfiddle.net/rniemeyer/NAgNV /

76
répondu RP Niemeyer 2013-09-06 01:40:05

j'ai dû faire une légère modification au code RP de Niemeyer pour travailler dans mon code en utilisant l'option dateFormat, en remplaçant

$(element).datepicker("getDate")

avec

$(element).val()

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

6
répondu OddEssay 2012-05-24 08:47:35

j'ai utilisé le code RP de Niemeyer marqué comme la réponse ci-dessus, mais depuis que je l'ai utilisé j'ai fait quelques petits changements à elle. J'ai pensé que je poste ici. Peut-être que ça 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 quand la page se charge alors il conservera sa valeur. En outre, j'ai fait $elem une variable de sorte qu'il y aura 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);
        }
    }
};
6
répondu Evan Larsen 2013-10-27 12:03:30

Voici ce qui a fonctionné pour mon ensemble particulier de circonstances. J'exécute une nouvelle version de MVC, que le serialiseur datetime par défaut rend à ISO 8601 (voir sur le cauchemar qui est JSON Dates. De plus, JSON.NET et ASP.NET API Web ). Mes reliures n'écrivent pas directement au sélectionneur de date, mais plutôt à l'attribut" value " d'une étiquette d'entrée.

aussi, je note, 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"));
        });
    }
}

Liaison ressemble à ceci:

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

et le code JavaScript pour activer le curseur de données:

$(document).ready(function () {
    $('.date').datepicker({ dateFormat: "mm/dd/yy" });
});
2
répondu viggity 2015-01-18 04:00:39

les exemples ci-dessus du lecteur de données changent le format de la date dans le modèle de vue de WCF au format de date JavaScript lorsque l'utilisateur sélectionne une nouvelle date à partir du contrôle du lecteur de données.

dans mon cas, je passais la date à un service WCF, et il n'acceptait pas une date JavaScript désérialisée, il avait besoin de la date dans le format WCF. J'ai modifié le script ci-dessus pour qu'il stocke la date dans le viewmodel au format WCF pour que il peut être renvoyé 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, "")));
        }
        current = $(element).datepicker("getDate");
        if (value - current !== 0) {
            $(element).datepicker("setDate", value);
        }
    }
};
1
répondu Russellg 2013-10-27 12:07:03

une solution est de formater la date vous-même dans la fonction fiable observable. Donc vous devez retourner quelque chose comme return viewModel.someOtherObservable() dans la fonction. Formater la valeur de retour.

si vous incluez votre code, je peux vous en dire plus.

0
répondu neebz 2013-10-27 12:00:27

le formatage de la date (en mm / jj / aaaa) à l'intérieur de l'observable fiable est exactement ce que je me demandais comment faire. Je posterai un peu de mon code si vous pouvez aider, Peter Mortensen et/ou nEEBz.

    <div data-bind="with: technology">  
        <div class="titleblock">
            <label><b>End of Life Date</b></label> 
            <Input  type="text" class="ui-datepicker" id="datepicker" data-bind="value: END_OF_LIFE_DATE"/>
        </div>       
    </div>

dans le ViewModel - technologydetail.js:

var technology = ko.observable();

dans l'Activer:

return dataContext.getTechnologyById(currentTechnologyId, technology);

cela affiche une date qui ressemble à cela dans la zone de texte: Mer Jan 29 19:00: 00 EST 2014 mais Je veux juste vous montrer: 29/01/2014. J'utilise cette option de curseur de données-dateFormat: "mm/dd / yy" mais elle n'a aucun effet sur la valeur initiale affichée.

j'ai pu le formater en utilisant moment et il fonctionne bien pour afficher la valeur actuelle de la base de données, mais il semble casser la reliure de nouveau à l'observable parce qu'il ne sera plus mis à jour sur une sauvegarde.

<Input type="text" class="ui-datepicker" id="datepicker" data-bind="value: moment(END_OF_LIFE_DATE()).format('MM/DD/YYYY')" />
0
répondu Debbie A 2014-01-22 17:50:59