2012-06-07 2 views
5

Я пытаюсь создать настраиваемый bindHandler, который я могу использовать для создания поведения водяных знаков для полей ввода текста.текстовый ввод водяного знака с использованием пользовательского связыванияHandler

По watermark я имею в виду: добавить значения по умолчанию для текстовых полей, которые удаляются в центре внимания, и заменены на размытие, если текстовое поле еще пуст

мне удалось получить эту работу, как показано в этом jsfiddle : http://jsfiddle.net/rpallas/nvxuw/

у меня есть 3 вопроса по поводу этого решения:

  1. есть ли способ изменить его так, что я только должен объявить значение водяного знака один раз? В настоящее время я должен поставить его на место, где я объявляю привязку, и мне также нужно инициализировать наблюдаемое с тем же значением в viewModel, поскольку в противном случае оно не будет иметь начального значения.
  2. Есть ли лучший способ добраться до лежащего ниже наблюдаемого, к которому привязано значение элементов. Я сейчас хватаю его, используя allBindingsAccessor, но это мне не нравится. Первоначально я просто установил значение, используя jquery $(element).val(''), но это также не так. Что лучше, или есть лучший способ?
  3. Есть ли у кого-нибудь или существуют существующие решения этой проблемы? Я заново изобретаю колесо?

ответ

14

Я думаю, что вы используете allbindings не нужно. На самом деле я не думаю, что водяной знак должен быть осведомлен о наблюдаемом вообще, так как это то, что водяной знак обычно имеет атрибут placeholder.

Будет ли это работать на вас?

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/

Надеется, что это помогает.

+1

Да, это почти то, что у меня было до того, как я изменил его, чтобы использовать allBindingsAccessor. При попытке установить начальное значение мне не хватало 'setTimeout'. Не могли бы вы кратко объяснить, почему это требуется? Кроме того, знаете ли вы, есть ли лучший способ? или вы думаете, что это хороший (достаточно) способ (с точки зрения всего решения)? Например, я замечаю, что есть привязка hasfocus (встроенная). Может быть, это лучший подход? – Robbie

+2

Я думаю, что этот подход подходит, если вы хотите поддерживать старые браузеры. Для новых просто используйте атрибут placeholder. SetTimeout необходим, потому что внутри KO использует setTimeout перед установкой значения ввода. Это означает, что ваш код работал до того, как код KO установил значение, поэтому вам нужно, чтобы setTimeout снова удостоверился, что ваш код пришел последним в выполнении. – madcapnmckay

+0

Большое спасибо за объяснение и помощь. – Robbie

1

Предыдущий подход хорош до тех пор, пока ваша прикладная логика очень проста, имейте в виду, что решение возится со значениями вашей модели просмотра, эти значения могут быть наблюдаемыми, и у них могут быть связанные с ним подписки или вычисления, поэтому изменив значение, которое вы измените модель просмотра. Вот другое решение без обновления вашей модели просмотра.

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