2014-01-23 8 views
11

Я хотел бы использовать эту технику: make an input only-numeric type on knockoutНокаут пользовательский числовой привязки

, чтобы позволить пользователю вводить только цифры.

Однако этот метод не обновляет наблюдаемое значение в пользовательском интерфейсе.

HTML:

<span data-bind="text: Interval" ></span> 
<input data-bind="numeric: Interval" /> 

Переплет:

ko.bindingHandlers.numeric = { 
    init: function (element, valueAccessor) { 
     $(element).on("keydown", function (event) { 
      // Allow: backspace, delete, tab, escape, and enter 
      if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 || 
       // Allow: Ctrl+A 
       (event.keyCode == 65 && event.ctrlKey === true) || 
       // Allow: . , 
       (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) || 
       // Allow: home, end, left, right 
       (event.keyCode >= 35 && event.keyCode <= 39)) { 
       // let it happen, don't do anything 
       return; 
      } 
      else { 
       // Ensure that it is a number and stop the keypress 
       if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) { 
        event.preventDefault(); 
       } 
      } 
     }); 
    }  
}; 

Таким образом, связывание не позволяет ввести другие, чем числа символов, но когда фокус теряется на input, что соответствует наблюдаемым не обновляется (поэтому span элементы не меняются).

Примечание:

мне не нужно, чтобы позволить пользователю вводить не числовые символы на вход. Я знаю, что есть другое решение, такое как числовое расширение ko, которое преобразует все в числовые числа, но мне это не нужно. Мне нужно решение, которое позволяет вводить только цифры (включая что-то вроде backspace и т. Д.).

+1

Можете ли вы создать рабочий скрипт, отображающий проблему? –

+0

Вы забыли включить - для отрицательных чисел –

ответ

1

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

Однако в вопросе, который вы связали, в комментариях есть лучший подход. Это использовать расширитель нокаута. См. Живой пример 1 на http://knockoutjs.com/documentation/extenders.html

Есть несколько причин, по которым это лучше: 1. Более прочный. Например, вы все равно можете вставить строку текста из буфера обмена в своем решении. 2. Удобство. Ваше решение явно отключает кучу ключей. Это совсем не удобно. Решение, предложенное Knockout, просто гарантирует, что конечная ценность является правильной. 3. Лучшее разделение кода и ремонтопригодность: ваш HTML может содержать простое связывание значений. Как только возникает требование о том, что значение должно быть числовым, вы просто расширяете наблюдаемое в своей модели viewmodel. Единственное изменение, которое вы делаете, - это JavaScript, как и должно быть, поскольку это функциональность, а не презентация. Это изменение также само по себе, и очень ясно, что расширитель делает для любого, кто может использовать наблюдаемые в вычислениях или без учета.

+0

Я видел этот пример, но в моем случае мне действительно не нужно позволять вводить другие значения только числа. Таким образом, такой расширитель не соответствует моим потребностям. – renathy

6

Твердый маршрут для числовых номеров будет для пользователя расширителем.

Нам не нужно отслеживать нажатия клавиш. Легче просто подписаться на наблюдаемое, чтобы перехватить значение до его обновления. Затем мы можем сделать некоторое регулярное выражение, которое позволяет нам оценить, является ли ввод числом или нет. Если вход не является числом, мы будем вычеркивать нечисловые символы. Таким образом, не допускается числовой ввод.

FIDDLE:

HTML

<input type="text" data-bind="value: myNum, valueUpdate: 'afterkeyup'" /> 

JS

(function(ko) { 

    ko.observable.fn.numeric = function() { 
     // the observable we are extending 
     var target = this; 

     // subscribe to the observable so we can 
     // intercept the value and do our custom 
     // processing. 
     this.subscribe(function() { 
      var value = target(); 
      // this will strip out any non numeric characters 
      target(value.replace(/[^0-9]+/g,'')); //[^0-9\.]/g - allows decimals 
     }, this); 

     return target; 
    }; 

    function ViewModel() { 
     this.myNum = ko.observable().numeric(); 
    }; 

    ko.applyBindings(new ViewModel()); 

})(ko); 
+0

Любите этот подход. Отличное решение. – pimbrouwers

1

Я хотел бы предложить вам сделать обертку вокруг http://numeraljs.com/.Вы просто подключаете настройки и при обновлении вы будете вызывать формат на входе.

0

Вы можете улучшить свои привязки обработчика для поддержки модификации valueAccessor

Переплет:

ko.bindingHandlers.numeric = { 
    init: function (element, valueAccessor) { 
     var value = valueAccessor(); 
     $(element).on("keydown", function (event) { 
      // Allow: backspace, delete, tab, escape, and enter 
      if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 || 
       // Allow: Ctrl+A 
       (event.keyCode == 65 && event.ctrlKey === true) || 
       // Allow: . , 
       (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) || 
       // Allow: home, end, left, right 
       (event.keyCode >= 35 && event.keyCode <= 39)) { 
       // let it happen, don't do anything 
       return; 
      } 
      else { 
       // Ensure that it is a number and stop the keypress 
       if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) { 
        event.preventDefault(); 
       } 
      } 
     }); 

     $(element).change(function() { 
      value($(element).val()); 
     }); 
    }  
}; 

В этом случае HTML будет

<span data-bind="text: Interval" ></span> 
<input data-bind="numeric: Interval" /> 

FIDDLE

1

Мне нужно решение, которое позволяет вводить только цифры (включая что-то вроде забой и т.д.).

Проверить это JQuery плагин: http://www.texotela.co.uk/code/jquery/numeric/

это позволяет десятичный разделитель, вы можете раскошелиться его для того, чтобы позволить другим символы как забой

1

Это моя фиксированная версия, учитывая все выше, но работая как привязка к реальным значениям и , поддерживая несущие объекты как источник/цель.

EDIT: уменьшенная версия нокаута не выставляет writeValueToProperty функции и twoWayBindings. Поэтому мы должны клонировать writeValueToProperty и использовать _twoWayBindings. Я обновил код, чтобы поддержать уменьшенную версию нокаута.

ko.expressionRewriting._twoWayBindings.numericValue = true; 
ko.expressionRewriting.writeValueToProperty = function (property, allBindings, key, value, checkIfDifferent) { 
    if (!property || !ko.isObservable(property)) { 
     var propWriters = allBindings.get('_ko_property_writers'); 
     if (propWriters && propWriters[key]) 
      propWriters[key](value); 
    } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) { 
     property(value); 
    } 
}; 
ko.bindingHandlers.numericValue = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     $(element).on("keydown", function (event) { 
      // Allow: backspace, delete, tab, escape, and enter. 
      if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 || 
       // Allow: Ctrl+A 
       (event.keyCode == 65 && event.ctrlKey === true) || 
       // Allow: . , 
       (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) || 
       // Allow: home, end, left, right. 
       (event.keyCode >= 35 && event.keyCode <= 39)) { 
       // Let it happen, don't do anything. 
       return; 
      } 
      else { 
       if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) { 
        event.preventDefault(); 
       } 
      } 
     }); 

     var underlying = valueAccessor(); 
     var interceptor = ko.dependentObservable({ 
      read: function() { 
       if (ko.isObservable(underlying) == false) { 
        return underlying; 
       } else { 
        return underlying(); 
       } 
      }, 
      write: function (value) { 
       if (ko.isObservable(underlying) == false) { 
        if (!isNaN(value)) { 
         var parsed = parseFloat(value); 
         ko.expressionRewriting.writeValueToProperty(underlying, allBindingsAccessor, 'numericValue', !isNaN(parsed) ? parsed : null); 
        } 
       } else { 
        if (!isNaN(value)) { 
         var parsed = parseFloat(value); 
         underlying(!isNaN(parsed) ? parsed : null); 
        } 
       } 
      } 
     }); 
     ko.bindingHandlers.value.init(element, function() { return interceptor; }, allBindingsAccessor, viewModel, bindingContext); 
    }, 
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext); 
    } 
} 
Смежные вопросы