Search code examples
knockout.jsknockout-validation

dependant validation in Knockout not working


I have a model which contains a multi select and a text box.

I want a validation to show up if none of them are populated, but no validation error if at least one of them is populated. (either one item in the select clicked, or some text).

I have a working plunkr here: plnkr.co/edit/pwKohFTmLPW1BKNwHxWR?p=preview

I tried thousands of things with no success. The problem at its core is that self.isValid() does not trigger the validation function SubscribersOrEmails

Currently I have this:

var ReportSchedule = function () {

   self.Subscribers = ko.observableArray().extend({ required: { onlyIf: function () { return self.SubscribersOrEmails === 0; } } });
   self.Emails = ko.observableArray().extend({ required: { onlyIf: function () { return self.SubscribersOrEmails === 0; } } });
   self.EmailText = ko.observable();

   self.SubscribersOrEmails = ko.computed(function () {
            var counter = 0;
            if (self.Emails != null && self.Subscribers != null) {
                counter = self.Emails().length + self.Subscribers().length;
            }
            console.log("counter: " + counter);
            return counter;
        });
}

I tried custom validators and every combination under the sun.

Any ideas what to try next?

I am using knockout v3.2.0-beta


Solution

  • This should solve it. Your computed expects the variables to exist, and your validation routine expects the computed to exist, so you need to separate the variables from their extensions.

    You were checking in the computed for whether the variables existed, but that prevented Knockout from figuring out the dependency.

    The required argument can just be self.subscribersOrEmails, you don't need to wrap it in a function.

    self.Subscribers = ko.observableArray();
    self.Emails = ko.observableArray();
    self.EmailText = ko.observable();
    self.Name = ko.observable();
    
    self.SubscribersOrEmails = ko.computed(function() {
      console.log("validation ");
      var counter = 0;
    
      console.log(self.Emails);
      console.log(self.Subscribers);
      counter = self.Emails().length + self.Subscribers().length;
      console.log("counter: " + counter);
      return counter == 0;
    });
    
    self.Subscribers.extend({
      required: {
        onlyIf: self.SubscribersOrEmails,
        params: 'Subscribers'
      }
    });
    self.Emails.extend({
      required: {
        onlyIf: self.SubscribersOrEmails,
        params: 'Emails'
      }
    });
    

    Also: you were overwriting Emails instead of setting its contents here:

    self.populateEmails = function() {
      self.Emails(self.getEmailsFromText(self.EmailText()));
    }
    

    And also here:

    $.each(self.schedulesViewModel.Schedules, function(index, schedule) {
      var emailsArray = schedule.getEmailsFromText(schedule.EmailText());
      schedule.Emails(emailsArray);
    });
    

    The error messages never get cleared because you have no code to clear them.