2012-06-20 5 views
21

Questa domanda è simile a knockoutjs databind with jquery-ui datepicker, ma invece di jQueryUI datepicker, vorrei utilizzare uno dei Bootstrap datepickers.Bootstrap datepicker con database knockout.js

L'API per il datepicker Bootstrap è diversa da jquery-ui e ho qualche problema a sistemarlo facendolo funzionare con knockout.js. Ho creato a jsFiddle to try it out.

Sembra che il bootstrap datepicker potrebbe essere molto più semplice da utilizzare perché non memorizza la data in modo indipendente. Tuttavia, vorrei sapere come se la jsFiddle è il modo più appropriato per utilizzare il widget Bootstrap datepicker con knockout.js cioè

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

     ko.utils.domNodeDisposal.addDisposeCallback(element, function() { 
      $(element).datepicker("destroy"); 
     }); 
    }, 
    update: function(element, valueAccessor) { 
    } 
}; 

risposta

40

Ecco un esempio di come è possibile raggiungere questo obiettivo con la DatePicker che si sta utilizzando :

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

     //when a user changes the date, update the view model 
     ko.utils.registerEventHandler(element, "changeDate", function(event) { 
      var value = valueAccessor(); 
      if (ko.isObservable(value)) { 
       value(event.date); 
      }     
     }); 
    }, 
    update: function(element, valueAccessor) { 
     var widget = $(element).data("datepicker"); 
     //when the view model is updated, update the widget 
     if (widget) { 
      widget.date = ko.utils.unwrapObservable(valueAccessor()); 
      if (widget.date) { 
       widget.setValue();    
      } 
     } 
    } 
}; 

Non sembrava che ci fosse alcuna funzionalità di distruzione, quindi ho rimosso quel pezzo. Questo gestisce l'evento changeDate dei widget per aggiornare il modello di visualizzazione, quando un utente modifica la data. La funzione update gestisce quando viene modificato il modello di visualizzazione per aggiornare il widget.

Se si desidera associare il valore a un non osservabile, occorrerebbe un po 'più di codice. Fammi sapere se è qualcosa che devi supportare.

http://jsfiddle.net/rniemeyer/KLpq7/

+2

Ecco a [jsFiddle] (http://jsfiddle.net/bmh_ca/uQcCx/2/) che ha una conversione stringa-> più amenable della data quando il campo viene aggiornato. Questo ha ancora l'avvertenza che cambia solo attraverso il widget sono registrati; apportare modifiche al campo di input non aggiorna il modello. –

+2

Ecco un aggiornamento per associare l'evento 'change' per rispondere alle modifiche al campo di input: http://jsfiddle.net/rniemeyer/uQcCx/3/ –

+0

JsFiddles non sembra funzionare più, hai fatto alcuni cambiamenti dal?, testato chrome e firefox, datepicker non si presenta più. Cheers – dtjmsy

2

Ecco quello che ho finito per

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

    var options = { 
     autoclose: true, 
     format: 'yyyy-mm-dd', 
    } 

    //var options = allBindingsAccessor().datepickerOptions || {}; 
    $(element).datepicker(options); 

    //when a user changes the date, update the view model 
    ko.utils.registerEventHandler(element, "changeDate", function (event) { 
     var value = valueAccessor(); 

     if (ko.isObservable(value)) { 
      var myDate = event.date; 
      var month = myDate.getMonth() + 1; 
      var monthText = month; 

      if (month < 10) 
       monthText = "0" + month; 

      var day1 = parseInt(myDate.getDate()); 
      var dayText = day1; 

      if (day1 < 10) 
       dayText = '0' + day1; 

      value(myDate.getFullYear() + '-' + monthText + '-' + dayText); 
     } 
    }); 
}, 
update: function (element, valueAccessor) { 

    var widget = $(element).data("datepicker"); 
    //when the view model is updated, update the widget 
    if (widget) { 
     widget.date = ko.utils.unwrapObservable(valueAccessor()); 
     widget.setValue(widget.date); 
    } 
}}; 
5

La risposta accettata non ha funzionato per me con la versione corrente del selettore di date. L'input non è stato inizializzato con il valore dell'osservabile. Ho effettuato una rilegatura aggiornata, a cui ho aggiunto questo:

$(element).datepicker('update', dataSource()); 

Questo sembra fare il trucco.

Ecco un violino aggiornato che utilizza la più recente selezione data disponibile, Bootstrap, jQuery, e Knockout: http://jsfiddle.net/krainey/nxhqerxg/

Aggiornamento:

ho sperimentato qualche difficoltà con la selezione data non giocare bene con il osservabile quando un utente modifica manualmente il valore nel campo di testo. Lo strumento analizzerebbe immediatamente la data e inserirà il risultato nel campo di input.

Se l'utente ha tentato di modificare il 10/07/2014, ad esempio, e ha utilizzato il backspace o elimina per rimuovere un numero (10/0/2014), il valore risultante verrà analizzato immediatamente e inserito nell'input di testo . Se il valore era, per un momento, il 10/0/2014, il selezionatore spostava il calendario sul 30/09/2014 e lo inseriva nel campo di testo. Se ho provato a modificare il mese e il valore era, per un momento, il 1/7/2014, il selezionatore si sarebbe spostato al 7 gennaio 2014 e lo avrebbe inserito nel campo di testo.

Si può vedere che il comportamento in questo violino:

http://jsfiddle.net/krainey/nxhqerxg/10/

ho dovuto aggiornare il mio legame con un gestore speciale per rilevare messa a fuoco, e associare un evento di sfocatura di una volta per farlo gestire manuale modifica correttamente.

$(element).on("changeDate", function (ev) { 
    var observable = valueAccessor(); 
    if ($(element).is(':focus')) { 
     // Don't update while the user is in the field... 
     // Instead, handle focus loss 
     $(element).one('blur', function(ev){ 
      var dateVal = $(element).datepicker("getDate"); 
      observable(dateVal); 
     }); 
    } 
    else { 
     observable(ev.date); 
    } 
}); 

il violino si fa riferimento nella risposta originale è stato aggiornato per riflettere questa:

http://jsfiddle.net/krainey/nxhqerxg/

5

mia versione attuale è un mix tra le soluzioni già illustrate:

ko.bindingHandlers.datepicker = { 
init: function (element, valueAccessor, allBindingsAccessor) { 

    var unwrap = ko.utils.unwrapObservable; 
    var dataSource = valueAccessor(); 
    var binding = allBindingsAccessor(); 

    //initialize datepicker with some optional options 
    var options = allBindingsAccessor().datepickerOptions || {}; 
    $(element).datepicker(options); 
    $(element).datepicker('update', dataSource()); 
    //when a user changes the date, update the view model 
    ko.utils.registerEventHandler(element, "changeDate", function (event) { 
     var value = valueAccessor(); 
     if (ko.isObservable(value)) { 
      value(event.date); 
     } 
    }); 
}, 
update: function (element, valueAccessor) { 
    var widget = $(element).data("datepicker"); 

    var value = ko.utils.unwrapObservable(valueAccessor()); 

    //when the view model is updated, update the widget 
    if (widget) { 
     widget.date = value; 
     if (widget.date) { 
      widget.setValue(); 
      $(element).datepicker('update', value) 
     } 
    } 
}};