2013-08-02 7 views
14

(to działa tylko w Chrome, w tej chwili, ponieważ większość przeglądarek jeszcze nie wdrażają wyboru daty dla input type = „date”)Używanie Knockout.js w jaki sposób powiązać właściwość Date z selektorem daty HTML5?

W poniższym przykładzie MyDate zaczyna się jako obiekt bieżąco z aktualną datą , ale nie jest to odbierane przez dane wejściowe daty (które oczekują, że jego format będzie ciągiem w formacie RRRR/MM/DD).

Po wybraniu daty w selektorze, MyDate staje się łańcuchem w powyższym formacie.

W jaki sposób można to powiązać, aby MyDate pozostała datą javascript i została poprawnie zinterpretowana przez kontrolę wejścia?

See Zobacz 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> 

Odpowiedz

9

Podczas gdy odpowiedź @amakhrov będzie działała (i byłaby jeszcze lepsza, gdyby była używana do zapisu możliwego do zapisania jak sujested przez @Stijn) Postanowiłem zrobić to za pomocą Custom Bindings.

Główną zaletą tego jest wielokrotność użycia - po prostu muszę użyć data-bind="datePicker : MyDate" wszędzie tam, gdzie chcę to powiązać. Mogę także zmodyfikować inne właściwości elementu wejściowego, tak by było to naprawdę użyteczne, gdyby wiązało się ze złożonym jQuery (i inne) kontrole.

(Read here for more pro/cons o 3 wyborów robić tego typu rzeczy)

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); 

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

+5

Czy to nadal działa? Mój datepicker chrome odmawia wyświetlania dowolnej daty - tylko "mm/dd/rrrr" w polu, nawet gdy wybieram nowe daty, a nawet jak pojawiają się w wydruku dziennika. Czy wiesz, jak to naprawić? Walczę. –

+1

@ uosɐs To nie działało dla mnie, dopóki nie zacząłem wywoływać 'ko.unwrap (valueAccessor())' w funkcji aktualizacji. – jbarz

+0

Nie działa, dodaj viewModel.MyDate ("2/2/2012"); na dole skrzypiec i zobaczyć, że data w selektorze nie aktualizuje się. – pilavdzice

7

Można użyć komputerowej vartiable dla obiektu daty w swoim modelu

W HTML:

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

w postaci kodu:

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) 

Proszę zobaczyć demo: http://jsfiddle.net/gcAXB/1/

+0

To nie ustawia wartości selektora przy początkowym załadowaniu - podejrzane, że trzeba ustawić rawDate na ciąg ISO w MyDate? – Ryan

+0

Masz rację. Data nie była wyświetlana w twoim oryginalnym przykładzie, więc zapomniałem dodać też :) Zobacz zaktualizowany kod i wersję demo powyżej. – amakhrov

+0

Dziękuję za odpowiedź, czy mógłbyś dać mi jakiś pomysł na temat datepicker html5 (typ wejścia "date") z knockout.js bez użycia zmiennych obliczeniowych? tak jak to jest tutaj: http://screencast.com/t/pMtuSV6mxUf – johannesMatevosyan

1

Od HTML 5 - Input type date formatting on iOS

Istnieją dwa formaty w grę:

  • wyświetlanego formatu
  • wewnętrzny format narażone na JavaScript i wysyłane do serwera

Nie można zmienić formatu wyświetlania. Od przeglądarki zależy, czy użytkownik poda datę (w praktyce jest ona określana przez ustawienia regionalne systemu na ).

Nie można również zmienić formatu wewnętrznego. Zawsze jest to ISO8601, niezależnie od przeglądarki/ustawień regionalnych.

Musisz wstępnie wypełnić go z tym konkretnym formacie i można dodać obliczane obserwowalne do analizowania go w Date obiektu, dzięki czemu można go odczytać w innych miejscach w aplikacji.

Jeśli chcesz napisać do niego z JS, możesz skonfigurować writeable computed observable i przeanalizować dane wejściowe, aby sprawdzić, czy jest to ciąg znaków z pola wejściowego, lub obiekt Date ze swojego JS.

6

Oto rozwiązanie, które jest pracując dla m e z najnowszymi knockoutjs, opartymi na poniższym łączu i zmodyfikowanymi tak, aby miały niestandardową funkcję init do obsługi aktualizacji właściwości ko.computed w miarę zmiany wartości daty.

Zauważ, że utils.formatDate to tylko funkcja użyteczna do sformatowania daty w dowolnym łańcuchu, który chcesz, więc po prostu zamień go na własny kod formatowania daty, bez względu na to, czy używasz instantjs, czy czegoś innego.

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> 

BINDING AND FORMATTING DATES USING KNOCKOUT AND MOMENT JS

+0

Link w poście nie działa, to jest mój kod dla MomentJS: http://www.cederlof.net/knockout-binding-to-javascript-dates-and-moment-formatting/ – cederlof

+1

FYI dla przyszłej wiedzy, artykuł Jason Mitchell na ten temat (link z góry) jest teraz na tym [link] (https://json.codes/blog/binding-and-formatting-dates-using-knockout-and-moment) (na dzień dzisiejszy) – t1nr2y

2

Opierając się odpowiedzi Ryana powyżej, działa to trochę ładniejszy z nowszymi ko/chrom widgetów. Usuwa również część czasu w czasie.

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; 
     } 
    } 
}; 
+0

Musiałem użyć zdarzenia zamazywania zamiast zdarzenia zmiany, aby to zadziałało. Chrome 44.0.2403.39 beta-m (64-bitowy), knockout.js 3.10 – jrockers

+0

Od 2/27/18 nie jestem w stanie uzyskać tej odpowiedzi do pracy. – azulBonnet

1

dzisiejszych czasach jest tak dużo łatwiejsze Moment.js

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 

w HTML można powiązać go z

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

i wyświetlić go sformatowany jako

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

Nie trzeba tworzyć niestandardowych powiązań, a y możesz użyć podkładki w starszych przeglądarkach.

+0

Myślę, że to powinna być nowa odpowiedź, działa jak urok. –

2

Ten sam zwyczaj wiązania za pomocą 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"); 
    } 
}; 
+0

Czy możesz mi powiedzieć dlaczego, kiedy zmieniłem format w aktualizacji (jak: element.value = moment (wartość()) .format ("DD-MM-RRRR");) aktualizuje moje dane w formacie MM-DD-RRRR ? – Kadaj

0

ten pracował dla mnie

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"/>