2012-11-28 10 views
5

Sto tentando di sperimentare e vedere se esistono soluzioni intelligenti per la creazione di validatori personalizzati che possono essere astratti per nitidezza e riutilizzo.Convalida osservabileArray contro una condizione

Nel jsfiddle di seguito, ho appena creato un modello genitore semplice che memorizza e una serie di misure (solo un valore e una data). In questo esempio, ho inserito due requisiti.

  1. Ogni misura ha entrambi i campi forniti o nessuno dei due deve essere fornito.
  2. Deve esserci almeno una misura valida (soddisfa la condizione precedente) nell'array padre.

    Idealmente, voglio la logica di validazione per ciò che definisce essere valido, memorizzato all'interno dell'oggetto Measurement come ho fatto di seguito. Ma, la cosa di cui sono molto dispiaciuto è la convalida "hands-on" che devo eseguire nel modello principale in atLeastOne().

convalida Knockout convaliderà automaticamente i campi individuali per numeri e le date MA, devo intervenire e eseguire la convalida contro la regola per l'array.

Domanda: Sono le eventuali approcci che mi permettono di impostare la convalida KO per verificare la matrice per questo la condizione richiesta, pur avendo il metodo HasValues ancora risiedono nel Modello Misura ??? Vale a dire, voglio astrarre il concetto di cercare "almeno uno" in un validatore personalizzato di qualche tipo che possa gestire il lavoro per me, e poi dire semplicemente questo validatore "hey, ecco la funzione che voglio che tu usi per convalidare ogni elemento nell'array. "

Grazie in anticipo!

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

Ecco un jsfiddle per giocare con che ha il mio esempio: http://jsfiddle.net/cACZ9/

risposta

7

ho gingillarsi la fonte biblioteca per vedere se riuscivo a scoprire qualcosa che potrebbe essere una valida opzione. Ecco cosa ho trovato finora.

due diverse opzioni, sia con vantaggi/svantaggi (ovviamente):

Uso personalizzato Validator:

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

Questo approccio prende più o meno la convalida dalle mani del programmatore ed è molto riutilizzabile . Tuttavia, ho notato che un potenziale cono è che chiamerà la regola di convalida personalizzata ogni volta che qualsiasi valore memorizzato all'interno della matrice (oggetti o altro) è mutato. Potrebbe non essere un problema per la maggior parte.

Utilizzando una fabbrica validatore:

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

Questo approccio può assicurare convalidare solo l'intero array quando si sceglie esplicitamente di farlo. Il rovescio della medaglia è che hai più lavoro pratico e non sfrutta appieno la libreria di validazione a eliminazione diretta. Devi specificamente convalidare la matrice e tutti/tutti gli altri osservabili che adottano questo approccio che potrebbe diventare potenzialmente disordinato se ce ne fossero molti.

Incoraggio modifiche e suggerimenti su questi approcci.

Problemi correlati