it-swarm.com.de

Verwenden von Knockout.js Wie bindet man eine Date-Eigenschaft an eine HTML5-Datumsauswahl?

(Dies funktioniert derzeit nur in Chrome, da die meisten Browser die Datumsauswahl für den Eingabetyp = "Datum" noch nicht implementieren.)

Im folgenden Beispiel beginnt MyDate als Date-Objekt mit dem aktuellen Datum. Dieses Datum wird jedoch nicht von der Datumseingabe erfasst (die erwartet, dass das Format ein String im Format JJJJ/MM/TT ist).

Sobald Sie ein Datum in der Auswahl ausgewählt haben, wird MyDate zu einer Zeichenfolge im oben genannten Format.

Wie können Sie dies binden, damit MyDate ein Javascript-Datum bleibt und vom Eingabesteuerelement richtig interpretiert wird?

Siehe http://jsfiddle.net/LLkC4/3/ : -

<input data-bind="value : MyDate" type="date">
<hr>   
<span data-bind="html: log" />

<script>
var viewModel = {    
    MyDate : ko.observable(new Date()),
    log : ko.observable(""),
    logDate : function () { 
            this.log(this.log() + this.MyDate() + " : " +
                     typeof(this.MyDate()) + "<br>");
                     }
};

viewModel.MyDate.subscribe(function (date) {    
    viewModel.logDate();    
});

ko.applyBindings(viewModel);

viewModel.logDate()
</script>
14
Ryan

Während die Antwort von @amakhrov funktionieren wird (und noch besser wäre, wenn sie schreibbar berechnet und beobachtbar wie von @Stijn verwendet wird), entschied ich mich, dies mit Custom Bindings zu tun.

Der Hauptvorteil dabei ist die Wiederverwendbarkeit. Ich muss data-bind="datePicker : MyDate" überall dort verwenden, wo ich dies binden möchte. Ich kann auch andere Eigenschaften des Eingabeelements ändern, sodass dies sehr nützlich sein kann, wenn an komplexe jQuery-Steuerelemente (und andere) gebunden wird.

( Lies hier für mehr Pro/Cons über die 3 Möglichkeiten, diese Art von Dingen zu machen)

HTML

<input data-bind="datePicker : MyDate" type="date">

JS

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {                    
        // Register change callbacks to update the model
        // if the control changes.       
        ko.utils.registerEventHandler(element, "change", function () {            
            var value = valueAccessor();
            value(new Date(element.value));            
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value =  valueAccessor();        
        element.value = value().toISOString();
    }
};

var viewModel = {    
    MyDate : ko.observable(new Date())
};     

ko.applyBindings(viewModel);

Siehe http://jsfiddle.net/LLkC4/5/

9
Ryan

Sie können den berechneten Wert für das Datumsobjekt in Ihrem Modell verwenden:

In HTML:

<input data-bind="value : rawDate" type="date">

In Code:

var currentDate = (new Date()).toISOString().split('T')[0];

// this is used instead of MyDate in the data binding
rawDate : ko.observable(currentDate),

...
// and then set up the dependent variable
viewModel.MyDate = ko.computed(function () {
    var val = this.rawDate();
    if (typeof val === 'string') val = new Date(val);

    return val;
}, viewModel)

Bitte sehen Sie sich die Demo an: http://jsfiddle.net/gcAXB/1/

7
amakhrov

Hier ist eine Lösung, die für mich mit den neuesten Knockoutjs funktioniert, basierend auf dem Link unten und modifiziert, um eine benutzerdefinierte Init-Funktion zu haben, die die Aktualisierung von ko.computed-Eigenschaften bei Änderungen des Datumswerts vornimmt.

Beachten Sie, dass utils.formatDate nur eine Dienstprogrammfunktion zum Formatieren des Datums in der von Ihnen gewünschten Zeichenfolge ist. Ersetzen Sie also das Datum durch Ihren eigenen Datumsformatierungscode, egal, ob Sie momentjs oder etwas anderes verwenden.

ko.bindingHandlers.date = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {    
        ko.utils.registerEventHandler(element, 'change', function () {
            var value = valueAccessor();

            if (element.value !== null && element.value !== undefined && element.value.length > 0) {
                value(element.value);
            }
            else {
                value('');
            }
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);

        var output = '';
        if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0) {
            output = utils.formatDate(valueUnwrapped);
        }

        if ($(element).is('input') === true) {
            $(element).val(output);
        } else {
            $(element).text(output);
        }
    }
};

    <div>
        <label>Date of Birth:</label>
        <input type="text" data-bind="date: dateOfBirth, format: 'DD MMM YYYY'" />
    </div>

BINDEN UND FORMATIEREN VON DATEN MIT KNOCKOUT UND MOMENT JS

6
Justin

Mit Moment.js ist es heutzutage viel einfacher

this.sessionDate = ko.observable(moment().format('YYYY-MM-DD'));
this.getFormattedDate = () => { return moment(this.sessionDate()'YYYY-MM-DD').format('MM/DD/YYYY') }; // Note this is ES2015 syntax

In Ihrer HTML-Datei können Sie es mit binden

<input class="form-control" name="date" type="date" id="date" data-bind="value: sessionDate">

Und es als formatiert anzeigen

<p data-bind="text : getFormattedDate()">Loading Date</p>

Sie müssen keine benutzerdefinierten Bindungen erstellen, und Sie können ein Shim für ältere Browser verwenden.

3
brianlmerritt

Basierend auf der obigen Antwort von Ryan ist dies mit neueren ko/chrome-Widgets etwas schöner. Außerdem wird der Uhrzeitteil des Datums entfernt.

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        // Register change callbacks to update the model
        // if the control changes.
        ko.utils.registerEventHandler(element, "change", function () {
            var value = valueAccessor();
            var target_date = element.valueAsDate;
            var truncated = new Date(target_date.getFullYear(), target_date.getMonth(), target_date.getDate());
            value(truncated);
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value =  valueAccessor();
        var unwrapped = ko.utils.unwrapObservable(value());
        if(unwrapped === undefined || unwrapped === null) {
            element.value = '';
        } else {
            element.valueAsDate = unwrapped;
        }
    }
};
2
Brian Arsuaga

Die gleiche benutzerdefinierte Bindung mit momentJS

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        // Register change callbacks to update the model
        // if the control changes.
        ko.utils.registerEventHandler(element, "change", function () {
            var value = valueAccessor();
            value(moment(element.value).format());
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value =  valueAccessor();
        element.value = moment(value()).format("YYYY-MM-DD");
    }
};
2

Aus HTML 5 - Datumsformatierung des Eingabetyps unter iOS

Es gibt zwei Formate im Spiel:

  • angezeigtes Format
  • internes Format, das JavaScript ausgesetzt ist und an den Server gesendet wird

Sie können das Anzeigeformat nicht ändern. Es liegt am Browser, zu entscheiden wie das Datum dem Benutzer angezeigt wird (in der Praxis wird dies durch das Gebietsschema von System bestimmt).

Sie können das interne Format auch nicht ändern. Es ist immer ISO8601, unabhängig von Browser/Gebietsschema.

Sie müssen es mit diesem bestimmten Format vorab ausfüllen. Sie können ein berechnetes Observable hinzufügen, um es in ein Date-Objekt zu parsen, damit Sie es an anderen Stellen in Ihrer Anwendung lesen können.

Wenn Sie auch von JS aus darauf schreiben möchten, können Sie ein schreibbares berechnetes Beobachtbares einrichten und die Eingabe analysieren, um zu sehen, ob es sich um eine Zeichenfolge aus dem Eingabefeld oder um ein Date-Objekt aus Ihrem JS handelt.

1
Stijn

Das hat bei mir funktioniert

ko.bindingHandlers.momentDate = {
_parseDateTime: function (element, valueAccessor) {
    var value = valueAccessor();
    var valueUnwrapped = ko.utils.unwrapObservable(value);
    var datetime = moment(valueUnwrapped);
    var date = moment($(element).val(), 'YYYY-MM-DD');
    datetime = datetime.set({
        'year': date.get('year'),
        'month': date.get('month'),
        'date': date.get('date')
    });
    value(datetime.toDate());
},
init: function (element, valueAccessor) {
    function bind() {
        ko.bindingHandlers.momentDate._parseDateTime(element, valueAccessor);
    }
    $(element).change(bind).blur(bind);
},
update: function (element, valueAccessor) {
    var value = valueAccessor();
    var valueUnwrapped = ko.utils.unwrapObservable(value);
    var date = moment(valueUnwrapped);
    $(element).val(date.format('YYYY-MM-DD'));
}

};

<input type="date" data-bind="momentDate: $data.Date" class="form-control"/>
0
KillerKiwi