具有动态可观测性的KnockoutJS验证

KnockoutJS Validation with dynamic observables

本文关键字:KnockoutJS 验证 动态 可观      更新时间:2023-09-26

我正在使用这个插件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>

Fiddlehttp://jsfiddle.net/qGzfr/

我该如何做到这一点?

只有当Knockout解析绑定时,您的属性已验证,验证插件才会应用于绑定中。

换句话说:在属性绑定到UI之后,您不能向属性添加验证。

在您的示例中,您使用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());那样替换整个对象,Knockout并不总是能很好地处理,所以只更新属性而不丢弃整个对象是更好的做法。

不同的解决方案是使用with绑定,因为在with绑定内部,如果绑定属性发生更改,KO将重新评估绑定。

所以改变你的看法:

<!-- 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

我能够让它工作,这是所需的更改:

<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"

无法调用未定义的方法"group"