0

I'm using Knockout Validation to validate my model in a Durandal/KnockoutJS app. It's working fine, but I've run into a situation that I'm not sure how to handle. One of the things that users enter is a list of "instructors", and they can enter an arbitrary number of instructors. Each instructor has a "teaching percentage" value. The sum of all teaching percentages must add up to 100%.

I'm not sure how to setup the validation for this, because when I'm defining my model object for "Instructors", I can't reference an arbitrary number of other Instructor objects.

The best option I've been able to come up with is place a viewmodel computed observable that is the sum of all instructor teaching percentages, and validate that value as being 100.

Am I missing something? Is this a wise way to go about this situation? Broadly speaking, this question applies to any situation in which you have multiple model objects, and the validity of one of their properties is mutually dependent on properties on other objects.

E.g., ObjA.Heading is valid if it is a positive number, and ObjB.Heading is also positive; and the reverse is also true (ObjB.Heading is valid if it is a positive number, and ObjA.Heading is also positive).

Thanks for any input on how to handle this kind of situation.

Thanks!

Josh
  • 7,232
  • 8
  • 48
  • 75
  • 1
    That's exactly how I would handle it on the first run. If you think about the display, you might have a "totals" row which adds everything up. You'd be validating that "totals" view model which does the calculating, not the collection of other view models. Sounds like a valid approach to me! – Ryan Rahlf Jun 28 '13 at 17:01

1 Answers1

0

originally responded to the first comment, but i think it falls more into the answer category:

the tricky part is how does your sum/total computed observable know that a child view models "teaching percentage" value has actually changed? it's one thing to trigger the computed whenever an instructor is added/removed to the list, but modifying the value of an existing instructor calls for some extra work. In this case, I would recommend looking into knockout-postbox. its a pub/sub type library where your main VM can subscribe to changes that occur in other viewmodels observables. from there your computed can update based on those changes

not knowing exactly how your viewmodels look, it would work like this:

// in instructor VM
self.teachingPercentage= ko.observable(value).publishOn("teachingPercentageUpdated");

// in main VM
self.teachingPercentageTotal = ko.computed(function () {
    var total = 0;
    ko.utils.arrayForEach(self.instructors(), function (i) {
        total += i.teachingPercentage();
    });
    return total;
});
self.teachingPercentageTotal.subscribeTo("teachingPercentageUpdated");
self.teachingPercentageTotal.extend({ equal: 100 });

i didnt actually run this, assuming it works. theres probably some better ways to do it but this is the general idea.

Kevin Nacios
  • 2,843
  • 19
  • 31
  • I thought a ko.computed() was supposed to automatically detect if a dependent observable was changed, and thus recalculate itself and notify subscribers of the new value? – Josh Jun 28 '13 at 20:52
  • you know, you're right. i had used this approach to a separate issue and used a pub/sub implementation to do it, but in this situation, the computed can do it. experimented with the computed method here: http://jsfiddle.net/8UGLW/ where i used pub/sub was with multiple levels of sub view models that needed validation, and having it rerun through the validation grouping for everything every time anything changed was overkill. – Kevin Nacios Jun 28 '13 at 21:30