Проверка нокаута 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