根据条件验证observableArray

时间:2012-11-28 17:17:01

标签: knockout.js knockout-validation

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

在下面的jsfiddle中,我只是将一个简单的父模型放在一起,它存储和测量数组(只是一个值和一个日期)。在这个例子中,我提出了两个要求。

  1. 每个测量都提供两个字段,或者两者都不提供。
  2. 必须至少有一个有效(符合先前条件)测量 在父数组中。

    理想情况下,我想要确定有效的验证逻辑,存储在Measurement对象中,如下所示。但是,我非常讨厌的是我必须在atLeastOne()的父模型中执行的“动手”验证。

  3. Knockout验证会自动验证各个字段的数字和日期但是我必须介入并对阵列规则进行验证。

    问题:是否允许我设置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);
        };
    

    这是一个jsfiddle,有我的例子: http://jsfiddle.net/cACZ9/

1 个答案:

答案 0 :(得分:7)

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

两种不同的选择,包括利弊(当然):

使用自定义验证器:

 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!');
       };
   }

此方法可确保您在明确选择时仅验证整个阵列。从根本上说,你有更多的实际工作,并没有充分利用淘汰验证库。您必须专门验证数组和采用这种方法的任何/所有其他可观察对象,如果有很多可能会变得混乱。

我鼓励对这些方法进行编辑和建议。