Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout validation extend 'required only if' with observable parameter

Is there a way to extend an observable to make it required only if and observable is true, and that changes can be tracked?

For example, I got this custom extender:

ko.extenders.requiredOnlyIf = function (target, makeRequired) {
target.HasError = ko.observable();

function validate(newValue) {
    if (makeRequired) {
        target.HasError(newValue ? false : true);
    } else {
        target.HasError(false);
    }
}

   validate(target());
   target.subscribe(validate);
   return target;
}

And this observables:

self.Field1 = ko.observable().extend({ requiredOnlyIf : self.Field2() });
self.Field2 = ko.observable().extend({ requiredOnlyIf : self.Field1() });

This observables are dependant, so, if one is filled, the other must be filled too. But the extender only works fine when the value is binding the first time, but when the value of any of the observables is changed is not working.

like image 780
antonio_mg Avatar asked May 10 '26 16:05

antonio_mg


1 Answers

A couple of things:

  1. You need to pass the observables, not the observables' contents, when setting up the extensions. (You can't create Field1 based on Field2 before Field2 exists, either.)
  2. You need two subscriptions, so that if a change to one makes the other invalid, that is noticed.
  3. (update) Rather than subscriptions and an observable, you can use a computed

ko.extenders.requiredOnlyIf = function(target, makeRequired) {
  target.HasError = ko.pureComputed(() => {
    const otherHasValue = !!makeRequired();
    const targetHasValue = !!target();

    return otherHasValue && !targetHasValue;
  });

  return target;
}

self = {};

self.Field1 = ko.observable();
self.Field2 = ko.observable().extend({
  requiredOnlyIf: self.Field1
});
self.Field1.extend({
  requiredOnlyIf: self.Field2
});

ko.applyBindings(self);
.invalid {
  border-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="value: Field1, css: {invalid: Field1.HasError()}" />
<input data-bind="value: Field2, css: {invalid: Field2.HasError()}" />
like image 199
Roy J Avatar answered May 12 '26 06:05

Roy J