Проверка нокаута JS с динамическими наблюдаемыми
Я использую этот плагин https://github.com/ericmbarnard/Knockout-Validation, и я пытаюсь проверить динамически загружаемый объект.
JavaScript:
function VM() {
var self = this;
// This is a static observable, just to ensure that basic validation works fine.
self.static = ko.observable();
self.static.extend({required: true});
// This is the observable that will be updated to my model instance.
self.person = ko.observable({});
// This is an handler for manual trigger.
// I'm not even sure this is needed.
self.a = function(){
self.errors.showAllMessages();
self.staticErrors.showAllMessages();
}
// Here i'm loading current person from somewhere, i.e. a rest service.
self.load = function() {
// Update observable
self.person(new Model());
// Define validation rules
self.person().name.extend({required: true});
self.person().email.extend({required: true});
// Set person data
self.person().name('Long');
self.person().email('John');
// Set validators
self.errors = ko.validation.group(self.person);
self.staticErrors = ko.validation.group(self.static);
}
}
// Just a test model.
function Model() {
this.name = ko.observable();
this.email = ko.observable();
}
ko.validation.init();
var vm = new VM();
ko.applyBindings(vm);
Разметка
<ul>
<li>1. Hit "Load"</li>
<li>2. Hit "Show errors", or maunally change input data.</li>
</ul>
<button data-bind='click: load'>Load</button>
<br/>
<h1>This is working properly.</h1>
<input type='text' data-bind='value: static' />
<br/>
<h1>This is not working.</h1>
<input type='text' data-bind='value: person().name' />
<input type='text' data-bind='value: person().email' />
<br/>
<button data-bind='click: a'>Show errors</button>
Скрипки
http://jsfiddle.net/qGzfr/
Как мне сделать эту работу?
Ответы
Ответ 1
Плагин проверки правильности применяется только в ваших привязках, только если к моменту, когда привязка будет проанализирована с помощью нокаута, ваши свойства будут проверяться.
Иными словами: вы не можете добавить проверку на свойство после, свойство было связано с пользовательским интерфейсом.
В вашем примере вы используете пустой объект в self.person = ko.observable({});
как значение по умолчанию, поэтому, когда Knockout выполняет выражение data-bind='value: person().name'
, у вас нет свойства name
, поэтому проверка не будет работать, даже если вы затем добавьте свойство name
к вашему объекту.
В вашем примере вы можете решить эту проблему, изменив конструктор Model
, чтобы включить правила проверки:
function Model() {
this.name = ko.observable().extend({required: true});
this.email = ko.observable().extend({required: true});
}
И используйте пустой объект Model
как человек по умолчанию:
self.person = ko.observable(new Model());
И при вызове Load
не заменяйте объект person
, но обновляйте его свойства:
self.load = function() {
// Set person data
self.person().name('Long');
self.person().email('John');
}
Демо JSFiddle.
Примечание. Нокаут не всегда хорошо обрабатывается, если вы заменяете весь объект, например self.person(new Model());
, поэтому лучше всего обновлять свойства и не выбрасывать весь объект.
Другим решением было бы использовать привязку with
, потому что внутри привязки with
KO будет переоценивать привязки, если свойство bound изменяется.
Итак, измените свое мнение:
<!-- ko with: person -->
<input type='text' data-bind='value: name' />
<input type='text' data-bind='value: email' />
<!-- /ko -->
В этом случае вам нужно использовать null
как значение по умолчанию person
:
self.person = ko.observable();
И в вашем Load
вам нужно добавить подтверждение до, назначая ваше свойство person
, поэтому к тому времени, когда KO применяет привязки, ваши свойства имеют проверку:
self.load = function() {
var model = new Model()
model.name.extend({required: true});
model.email.extend({required: true});
self.person(model);
// Set person data
self.person().name('Long');
self.person().email('John');
}
Демо JSFiddle.
Ответ 2
Мне удалось заставить его работать, это необходимые изменения:
<head>
<script type="text/javascript" src ="knockout-2.3.0.js"></script>
<script type="text/javascript" src ="knockout.validation.min.js"></script>
</head>
<body>
<!-- no changes -->
<script>
function VM() { ... }
function Model() { ... }
// ko.validation.init();
var vm = new VM();
ko.applyBindings(vm);
</script>
</body>
Что было сделано?
- Включить KnockoutJS и плагин проверки.
- Привязка после добавления элементов. Помните, что страницы HTML анализируются сверху вниз.
Как вы могли сказать? В консоли появились следующие ошибки:
Невозможно прочитать свойство 'nodetype' из null
и
Невозможно вызвать метод 'group' из undefined