Ответ 1
Интересный вопрос! Здесь одно чистое решение KnockoutJS + VanillaJS. Могут быть некоторые морщины, кросс-браузер (я смотрю на вас, IE!) И грубые края. Дайте мне знать в комментариях или предложите обновление ответа, если хотите.
Правила ViewModel и Validation:
Правила проверки должны быть близки к свойствам ViewModel, подобно атрибутам в .NET. В документации для KnockoutJS предлагается использовать extenders для этой цели. Использование будет выглядеть так:
self.name = ko.observable("Bob-Martin");
self.name = self.name.extend({ regex: { pattern: "^[^0-9]*$", message: "No digits plz!" } })
self.name = self.name.extend({ regex: { pattern: "^[^-]*$", message: "No dashes plz!" } });
Код для расширителя:
Расширитель из документации хорош и прост. Здесь альтернатива, которая обрабатывает несколько ошибок проверки (хотя для некоторых правил с одним и тем же сообщением требуется некоторая работа):
ko.extenders.regex = function(target, options) {
options = options || {};
var regexp = new RegExp(options.pattern || ".*");
var message = options.message || "regex is mad at you, bro!";
// Only create sub-observable if it hasn't been created yet
target.errors = target.errors || ko.observableArray();
function validate(newValue) {
var matched = regexp.test(newValue);
if (!matched && target.errors.indexOf(message) == -1) {
target.errors.push(message);
}
else if (matched && target.errors.indexOf(message) >= 0) {
// TODO: support multiple extender instances with same
// message yet different pattern.
target.errors.remove(message);
}
}
validate(target()); //initial validation
target.subscribe(validate); //validate whenever the value changes
return target; //return the original observable
};
Шаблон для сообщений проверки:
Чтобы сделать просмотр DRY и валидацию ненавязчивым, я бы определил шаблон для ошибок проверки следующим образом:
<script type="text/html" id="validation">
<span data-bind="foreach: $data" class="errors">
<span data-bind='text: $data'> </span>
</span>
</script>
Вид:
Фактический вид может быть очень простым:
<p>Name: <input data-bind='valueWithValidation: name' /></p>
Ненавязчивый и СУХОЙ, потому что здесь нет разметки с сообщениями проверки. (Если вам нужна специальная разметка для вашей проверки, вы можете просто использовать привязку value
и создать раздельную разметку для name.errors
.)
Пользовательская привязка:
И пользовательская привязка просто сделала бы, чтобы:
- Внесите шаблон после поля ввода.
- Примените правильную привязку шаблона к
name
наблюдаемому как данные. - Передайте остальные на привязки
value
иvalueUpdate
.
Вот привязка (может потребоваться некоторое рефакторинг, а jQuery/javascript lovin '):
ko.bindingHandlers.valueWithValidation = {
init: function (element, valueAccessor, allBindingsAccessor) {
// Interception! Add validation markup to the DOM and
// apply the template binding to it. Some of this code
// can be more elegant, especially if you use jQuery or
// a similar library.
var validationElement = document.createElement("span");
element.parentNode.insertBefore(validationElement, element.nextSibling);
ko.applyBindingsToNode(validationElement, { template: { name: 'validation', data: valueAccessor().errors } });
// The rest of this binding is handled by the default
// value binding. Pass it on!
ko.applyBindingsToNode(element, { value: valueAccessor(), valueUpdate: 'afterkeydown' });
}
};
Demo:
Чтобы увидеть все это в действии, загляните в этот jsfiddle.