title: Validating observableArray against a condition
body: <p>I am trying to experiment and see if there are any clever solutions for creating custom validators that can be abstracted for neatness and reuse.</p>
  
  <p>In the jsfiddle below, I just put together a simple parent model that stores and array of Measurements (just a value and a date). In this example, I put in two requirements. </p>
  
  <ol>
  <li>Each Measurement has either both fields supplied, or neither must be supplied.</li>
  <li><p>There has to be at least one valid (meets previous condition) measurement
  in parent array.</p>
  
  <p>Ideally, I want the validation logic for what defines being valid, stored within the Measurement object as I have done below. But, the thing I am very distastful of is the "hands-on" validation I am having to perform in the parent model in <code>atLeastOne()</code>.</p></li>
  </ol>
  
  <p>Knockout validation will automatically validate the individual fields for numbers and dates BUT, I have to step in and perform validation against the rule for the array.</p>
  
  <p><strong>Question:</strong> Are the any approaches that allow me to setup KO validation to check the array for this the required condition while still having the <code>HasValues</code> method still reside in the Measurement Model??? I.e I want to abstract the concept of searching for "at least one" into a custom validator of some sort that can handle the job for me, and then just tell this validator "hey, here is the function I want you to use to validate each item in the array."</p>
  
  <p>Thanks in advance!</p>
  
  <pre><code>    function Model(data) 
      {
         var self = this;
          self.Measurements = ko.observableArray();
  
         for(var i = 0; i &lt; 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() &amp;&amp; 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()) &amp;&amp; 
                     self.Date() &amp;&amp; self.Date().length &gt; 0;
          };
  
          function isRequired() {
              return ko.utils.isNotNullUndefOrEmpty(self.Value()) || 
                     (self.Date() &amp;&amp; self.Date().length &gt; 0);
          }
      }
  
      ko.utils.isNotNullUndefOrEmpty = function (value) {
          return (typeof value === 'string' &amp;&amp; value.length &gt; 0) || 
                 (typeof value !== 'string' &amp;&amp; value);
      };
  </code></pre>
  
  <p>Here is a jsfiddle to play with that has my example:
  <a href="http://jsfiddle.net/cACZ9/" rel="noreferrer">http://jsfiddle.net/cACZ9/</a></p>