2012-06-07 18 views
5

Ho cercato di creare un bindingHandler personalizzato che possa essere utilizzato per conferire un comportamento filigrana ai campi di input del testo.filigrana di input testo utilizzando bindingHandler personalizzato

Con watermark intendo: per aggiungere i valori predefiniti ai campi di testo che vengono rimossi a fuoco, e sostituito sulla sfocatura se il campo di testo è ancora vuoto

sono riuscito a farlo funzionare come dimostrato in questo jsfiddle : http://jsfiddle.net/rpallas/nvxuw/

ho 3 domande su questa soluzione:

  1. esiste un modo per modificarlo in modo che ho solo dichiarare il valore filigrana volta? Attualmente devo metterlo sul posto dove dichiaro il binding e devo anche inizializzare l'osservabile con lo stesso valore nel viewModel - altrimenti non avrebbe alcun valore iniziale.
  2. C'è un modo migliore per arrivare al sottostante osservabile al quale il valore degli elementi è associato. Attualmente lo sto utilizzando utilizzando allBindingsAccessor, ma questo mi sembra sbagliato. Inizialmente stavo semplicemente impostando il valore usando jquery $(element).val('') ma anche questo mi sembrava sbagliato. Qual è il migliore, o c'è un modo migliore?
  3. Qualcuno ha o conosce una soluzione esistente a questo problema? Sto reinventando la ruota?

risposta

14

Penso che l'uso di allbindings non sia necessario. In effetti, non penso che la filigrana debba essere a conoscenza di ciò che è osservabile poiché è ciò che generalmente una filigrana attribuisce all'attributo placeholder.

Questo lavoro potrebbe funzionare?

ko.bindingHandlers.watermark = { 
    init: function (element, valueAccessor, allBindingsAccessor) { 
     var value = valueAccessor(), allBindings = allBindingsAccessor(); 
     var defaultWatermark = ko.utils.unwrapObservable(value); 
     var $element = $(element); 

     setTimeout(function() { 
      $element.val(defaultWatermark);}, 0); 

     $element.focus(
      function() { 
       if ($element.val() === defaultWatermark) { 
        $element.val(""); 
       } 
      }).blur(function() { 
       if ($element.val() === '') { 
        $element.val(defaultWatermark) 
       } 
      }); 
    } 
}; 

http://jsfiddle.net/madcapnmckay/Q5yME/1/

Spero che questo aiuti.

+1

sì, questo è quasi esattamente quello che avevo prima ho cambiato per utilizzare il allBindingsAccessor. Mi mancava il 'setTimeout' quando si tenta di impostare il valore iniziale. Potresti spiegare brevemente perché è necessario? Inoltre, sai se c'è un modo migliore? o pensi che questo sia un buon (abbastanza) modo (in termini di tutta la soluzione)? Per esempio noto che c'è un vincolo di hasfocus (incorporato). Potrebbe essere un approccio migliore? – Robbie

+2

Penso che questo approccio sia adatto se si vogliono supportare i browser più vecchi. Per i nuovi basta usare l'attributo segnaposto. Il setTimeout è necessario perché internamente KO utilizza un setTimeout prima di impostare il valore dell'input. Ciò significa che il tuo codice era in esecuzione prima che il codice KO impostasse il valore, quindi è necessario impostare setTimeout per assicurarti che il tuo codice arrivi per ultimo nell'esecuzione. – madcapnmckay

+0

Grazie mille per la spiegazione e l'aiuto. – Robbie

1

L'approccio precedente va bene fintanto che la logica della tua app è davvero semplice, tieni presente che la soluzione fa casino con i valori del tuo View Model, quei valori possono essere osservabili e possono avere abbonamenti o calcoli associati ad esso, quindi cambiando il valore si modifica il modello di vista. Ecco una soluzione diversa senza aggiornare il tuo View Model

ko.bindingHandlers.fakePlaceHolderWhenNeedIt = { 
    init: function (element, valueAccessor, allBindings, vm) { 
    if (!Modernizr.input.placeholder) { 
     var placeHolderVal = $(element).attr("placeholder"); 

     if (placeHolderVal != null || placeHolderVal != '') { 

      var $element = $(element); 
      var value = valueAccessor() 
      var valueUnwrapped = ko.utils.unwrapObservable(value); 


      $element.keyup(function() { 
       var inputValue = $(this).val(); 
       var $watermark = $(this).prev('.ie-placeholder'); 
       if (inputValue == null || inputValue == '') { 
        $watermark.show(); 
       } 
       else { 
        $watermark.hide(); 
       } 
      }); 

      var display = valueUnwrapped != null || valueUnwrapped != '' ? "block" : "none"; 
      var left = $element.position().left; 
      var top = $element.position().top; 
      var paddingLeft = $element.css('padding-left'); 
      var paddingRight = $element.css('padding-right'); 
      var paddingTop = $element.css('padding-top'); 
      var paddingBottom = $element.css('padding-bottom'); 

      var height = $element.css('height'); 
      var placeHolder = '<div class="ie-placeholder" style="position:absolute;left:' + left + ';top:' + top + ';padding-top: ' + paddingTop + ';padding-bottom: ' + paddingBottom + ';padding-left: ' + paddingLeft + ';padding-right: ' + paddingRight + ';height: ' + height + ';line-height:' + height + ';display:' + display + ';">' + placeHolderVal + '</div>'; 

      $(placeHolder).click(function() { $element.focus(); }).insertBefore(element); 
     } 
    } 
}, 
update: function (element, valueAccessor, allBindings, vm) { 
    if (!Modernizr.input.placeholder) { 
     var placeHolderVal = $(element).attr("placeholder"); 

     if (placeHolderVal != null || placeHolderVal != '') { 
      var $element = $(element); 
      var value = valueAccessor() 
      var valueUnwrapped = ko.utils.unwrapObservable(value); 

      var $watermark = $element.prev('.ie-placeholder'); 
      if (valueUnwrapped == null || valueUnwrapped == '') { 
       $watermark.show(); 
      } 
      else { 
       $watermark.hide(); 
      } 
     } 
    } 
}