Knockout.js 根据某个条件验证可观察性

Knockout.js 根据某个条件验证可观察性,knockout.js,knockout-validation,Knockout.js,Knockout Validation,我正在尝试,看看是否有任何聪明的解决方案来创建定制验证器,这些验证器可以抽象为整洁和重用 在下面的jsfiddle中,我只是建立了一个简单的父模型,用于存储度量值和度量值数组(只是一个值和一个日期)。在这个例子中,我提出了两个要求 每个测量都提供了两个字段,或者两个字段都不必提供 必须至少有一个有效(满足先前条件)测量值 在父数组中 理想情况下,我希望将定义有效的验证逻辑存储在度量对象中,如下所述。但是,我非常厌恶的是我必须在atlestone()中的父模型中执行的“动手”验证 敲除验证将自动验

我正在尝试,看看是否有任何聪明的解决方案来创建定制验证器,这些验证器可以抽象为整洁和重用

在下面的jsfiddle中,我只是建立了一个简单的父模型,用于存储度量值和度量值数组(只是一个值和一个日期)。在这个例子中,我提出了两个要求

  • 每个测量都提供了两个字段,或者两个字段都不必提供
  • 必须至少有一个有效(满足先前条件)测量值 在父数组中

    理想情况下,我希望将定义有效的验证逻辑存储在度量对象中,如下所述。但是,我非常厌恶的是我必须在
    atlestone()
    中的父模型中执行的“动手”验证

  • 敲除验证将自动验证数字和日期的各个字段,但是,我必须介入并根据数组的规则执行验证

    问题:是否有任何方法允许我设置KO验证以检查阵列是否符合要求的条件,同时测量模型中仍然存在
    HasValues
    方法???也就是说,我想将搜索“至少一个”的概念抽象到一个定制的验证器中,该验证器可以为我处理这项工作,然后告诉这个验证器“嘿,这是我希望您用来验证数组中每个项的函数。”

    提前谢谢

        function Model(data) 
        {
           var self = this;
            self.Measurements = ko.observableArray();
    
           for(var i = 0; i < data.length; i++)
               self.Measurements.push(new Measurement(data[i]));
    
            function hasAtLeastOne(){
               var atLeastOne = false;
                $.each(self.Measurements(), function(i, item) { 
                    if (item.HasValues()) { 
                       atLeastOne = true; 
                       return; 
                     } 
                });
                return atLeastOne;
            }
    
            self.Save = function() {               
                if (self.canSave() && atLeastOne())
                    alert('save');
                else
                    alert('arg!');
            };
    
            self.errors = ko.validation.group(self);
            self.canSave = ko.computed(function() {
                return self.errors().length == 0;
            });
        }
    
        function Measurement(data)
        {
           var self = this;
           self.Value = ko.observable(data.val);
           self.Date = ko.observable(data.date);
    
           self.Value.extend({ required: { onlyIf: isRequired }, number: true });
           self.Date.extend({ required: { onlyIf: isRequired }, date: true });
    
            self.HasValues = function() {
                return ko.utils.isNotNullUndefOrEmpty(self.Value()) && 
                       self.Date() && self.Date().length > 0;
            };
    
            function isRequired() {
                return ko.utils.isNotNullUndefOrEmpty(self.Value()) || 
                       (self.Date() && self.Date().length > 0);
            }
        }
    
        ko.utils.isNotNullUndefOrEmpty = function (value) {
            return (typeof value === 'string' && value.length > 0) || 
                   (typeof value !== 'string' && value);
        };
    
    功能模型(数据)
    {
    var self=这个;
    自我测量=ko.observearray();
    对于(变量i=0;i0;
    };
    函数isRequired(){
    返回ko.utils.isNotNullUndefOrEmpty(self.Value())||
    (self.Date()和&self.Date().长度>0);
    }
    }
    ko.utils.isNotNullUndefOrEmpty=函数(值){
    返回(typeof value=='string'&&value.length>0)|
    (值的类型!='string'&&value);
    };
    
    下面是一个可以使用的JSFIDLE,它有我的示例:

    我一直在找图书馆的资料来源,看看是否能找到一些可行的选择。这是我到目前为止发现的

    两种不同的选择都有优点/缺点(当然):

    使用自定义验证器:

     ko.validation.rules['AtLeastOne'] = {
            validator: function (array, predicate) {
                var self = this;
                self.predicate = predicate;
                return ko.utils.arrayFirst(array, function (item) {
                    return self.predicate.call(item);
                }) != null; 
            },
            message: 'The array must contain at least one valid element.'
        };
    
    
      function Modal() {
         var self = this;
         self.Measurements = ko.observableArray().extend({ AtLeastOne: function () {
            return this && this.HasValues();
         }
    
         ...//refer to OP
         ...
         ...
    
         self.Save() = function() {
             if (self.errors().length == 0)
               alert('Everything is valid, we can save!');
           else if (!self.Measurements.isValid())
               alert('You must have at least one valid item in the pot!');
         };
      });
    
     var KoValidationFactory = {
            AtLeastOne: function (measurements, validator) {
                return function () {
                    var self = this;
                    self.validator = validator;
                    return ko.utils.arrayFirst(measurements, function (measurement) {
                                return self.validator.call(measurement);
                            }) != null; 
                };
            }
    
       };
    
       function Modal() {
          var self = this;
          self.Measurements = ko.observableArray();
    
         ...//refer to OP
         ...
         ...
    
          self.Save = function () {
              var atLeastOneArrayValidator = KoValidationFactory.AtLeastOne(self.Measurements(), function () {
                   return this && this.HasValues();
           });
              var arrayWasValid = atLeastOneArrayValidator();
              if (arrayWasValid && self.errors() == 0)
                 alert('everything is good, we can save');
              else if (!arrayWasValid)
                 alert('You must have at least one item in the pot!');
           };
       }
    
    这种方法几乎使程序员不再需要验证,而且非常可重用。但是,我注意到一个潜在的缺点是,每当数组中存储的任何值(对象或其他对象)发生变化时,它都会调用自定义验证规则。对大多数人来说可能不是问题

    使用验证器工厂:

     ko.validation.rules['AtLeastOne'] = {
            validator: function (array, predicate) {
                var self = this;
                self.predicate = predicate;
                return ko.utils.arrayFirst(array, function (item) {
                    return self.predicate.call(item);
                }) != null; 
            },
            message: 'The array must contain at least one valid element.'
        };
    
    
      function Modal() {
         var self = this;
         self.Measurements = ko.observableArray().extend({ AtLeastOne: function () {
            return this && this.HasValues();
         }
    
         ...//refer to OP
         ...
         ...
    
         self.Save() = function() {
             if (self.errors().length == 0)
               alert('Everything is valid, we can save!');
           else if (!self.Measurements.isValid())
               alert('You must have at least one valid item in the pot!');
         };
      });
    
     var KoValidationFactory = {
            AtLeastOne: function (measurements, validator) {
                return function () {
                    var self = this;
                    self.validator = validator;
                    return ko.utils.arrayFirst(measurements, function (measurement) {
                                return self.validator.call(measurement);
                            }) != null; 
                };
            }
    
       };
    
       function Modal() {
          var self = this;
          self.Measurements = ko.observableArray();
    
         ...//refer to OP
         ...
         ...
    
          self.Save = function () {
              var atLeastOneArrayValidator = KoValidationFactory.AtLeastOne(self.Measurements(), function () {
                   return this && this.HasValues();
           });
              var arrayWasValid = atLeastOneArrayValidator();
              if (arrayWasValid && self.errors() == 0)
                 alert('everything is good, we can save');
              else if (!arrayWasValid)
                 alert('You must have at least one item in the pot!');
           };
       }
    
    这种方法可以确保仅在显式选择验证整个阵列时才进行验证。不利的一面是,您有更多的实际工作,它没有充分利用淘汰验证库。您必须特别验证数组和采用这种方法的任何/所有其他观测值,如果有很多,它们可能会变得混乱

    我鼓励对这些方法进行编辑并提出建议