Поле ввода номера в Knockout JS
Я пытаюсь создать поле ввода числа, которое будет принимать только числа.
Мой метод начального значения состоял в том, чтобы заменить значение и снова установить его.
Подход к подписке
function vm(){
var self = this;
self.num = ko.observable();
self.num.subscribe(function(newValue){
var numReg = /^[0-9]$/;
var nonNumChar = /[^0-9]/g;
if(!numReg.test(newValue)){
self.num(newValue.toString().replace(nonNumChar, ''));
}
})
}
ko.applyBindings(new vm())
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" data-bind="textInput: num" />
Ответы
Ответ 1
Я использую extender как user3297291 aswer.
Расширители - это гибкий способ форматирования или проверки наблюдаемых и более многоразового использования.
Вот моя реализация для числового расширителя
//Extender
ko.extenders.numeric = function(target, options) {
//create a writable computed observable to intercept writes to our observable
var result = ko.pureComputed({
read: target, //always return the original observables value
write: function(newValue) {
var newValueAsNum = options.decimals ? parseFloat(newValue) : parseInt(newValue);
var valueToWrite = isNaN(newValueAsNum) ? options.defaultValue : newValueAsNum;
target(valueToWrite);
}
}).extend({
notify: 'always'
});
//initialize with current value to make sure it is rounded appropriately
result(target());
//return the new computed observable
return result;
};
//View Model
var vm = {
Product: ko.observable(),
Price: ko.observable().extend({
numeric: {
decimals: 2,
defaultValue: undefined
}
}),
Quantity: ko.observable().extend({
numeric: {
decimals: 0,
defaultValue: 0
}
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
Ответ 2
Я думаю, вы можете разделить проблему на две части:
- Убедитесь, что пользователь может вводить только номера, или
- Убедитесь, что ваше значение viewmodel - это число, а не строка.
Если вам нужна только часть 1, я бы посоветовал использовать функции HTML по умолчанию (5):
<input type="number" step="1" />
<input type="text" pattern="\d*" />
Если вы хотите, чтобы пользователь не мог ввести ничего, кроме числа, и хотите использовать значение в вашей модели просмотра, я бы использовал расширитель. Расширяя наблюдаемое, вы можете изменить его значение до того, как будут запущены какие-либо подписки.
Документы с нокаутом предоставляют отличный пример на странице :
Обратите внимание, что при использовании расширителя вам больше не нужно беспокоиться об атрибуте pattern
или type
; нокаут мгновенно изменяет значение сразу после его установки.
ko.extenders.numeric = function(target, precision) {
//create a writable computed observable to intercept writes to our observable
var result = ko.pureComputed({
read: target, //always return the original observables value
write: function(newValue) {
var current = target(),
roundingMultiplier = Math.pow(10, precision),
newValueAsNum = isNaN(newValue) ? 0 : +newValue,
valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
//only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
} else {
//if the rounded value is the same, but a different value was written, force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
}).extend({
notify: 'always'
});
//initialize with current value to make sure it is rounded appropriately
result(target());
//return the new computed observable
return result;
};
var vm = {
changes: ko.observable(0),
myNumber: ko.observable(0).extend({
numeric: 1
})
};
vm.myNumber.subscribe(function() {
vm.changes(vm.changes() + 1);
});
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" data-bind="value: myNumber">
<div>2 times <span data-bind="text: myNumber"></span> is <span data-bind="text: myNumber() * 2"></span>.</div>
<div> Changes: <span data-bind="text: changes"></span></div>
Ответ 3
Использование Проверка нокаута | LIVE PEN:
<input data-bind="value: Number">
ko.validation.init();
function VM() {
var self = this;
self.Number = ko.observable().extend({
required: true,
pattern: {
message: 'Invalid number.',
params: /\d$/
}
});
}
ko.applyBindings(window.v=new VM());
Ответ 4
Ниже приведена привязка mimic от knockout
textInput
, но с пользовательским анализом. Заметьте, я знаю, это добавило несколько дополнительных строк дублированного кода, но я думаю, что это стоит.
Я думал о создании своего пользовательского кода, но изобретать колесо будет много проблем, поэтому он будет оценивать усилия команд Knockout и копировать их.
Только числовой - JSFiddle.
Только персонажи - JSFiddle
Я обновил код в следующих
- updateModel. Чтобы получить только проанализированное значение из элемента. Это предотвратит обновление некорректного значения.
- updateView. Чтобы проверить, введен ли пользователь неправильное значение. Если да, замените предыдущее значение, добавьте предыдущее значение как текущее значение и продолжите.
Юзабилити
Я попытался увеличить объем этой привязки за пределами этого вопроса. Я добавил специальные атрибуты данных (data-pattern
и data-flag
), чтобы создать регулярное выражение, которое будет анализироваться соответствующим образом.