0

Hi I need to create a custom validator that will be aplyed for each element of an observable array using knockout validation plugin. The structure of my object will look something like this when I post it to the server:

var viewModel = {
   evaluationFormDataContract: {
       studentAssignmentInstanceId: value,
       evaluationType: value,
       categories: array[
       CategoriesOnEvaluationDataContract1 = {
           memo: value,
           categoryId: value,
           title: value,
           // Fields needed for validation
           hasMemo: value,
           memoIsMandatory: value
           questions: array[
           QuestionsOnEvalCategoryDataContract1 = {
               memo: value,
               grade: value,
               hasGrade: value,
               hasMemo: value,
               showOnlyMemo: value
           },
           QuestionsOnEvalCategoryDataContract2 = {
               memo: value,
               grade: value,
               hasGrade: value,
               hasMemo: value,
               showOnlyMemo: value
           }]
       },
       CategoriesOnEvaluationDataContract2 = {
           memo: value,
           categoryId: value,
           title: value,
           // Fields needed for validation
           hasMemo: value,
           memoIsMandatory: value
           questions: array[
           QuestionsOnEvalCategoryDataContract1 = {
               memo: value,
               grade: value,
               hasGrade: value,
               hasMemo: value,
               showOnlyMemo: value
           },
           QuestionsOnEvalCategoryDataContract2 = {
               memo: value,
               grade: value,
               hasGrade: value,
               hasMemo: value,
               showOnlyMemo: value
           },
           QuestionsOnEvalCategoryDataContract3 = {
               memo: value,
               grade: value,
               hasGrade: value,
               hasMemo: value,
               showOnlyMemo: value
           }]
       }, ]
   }

}

Now the validation will have to be applyed only on the two nested arrays and will be done based on some properties.

The first validation has to be done on each object of the categories array and it will check if hasMemo and memoIsMandatory if this is the case memo will be required.

The second validation will be done on each object of questions array and it will check if hasGrade if that is the case grade will be required.

The last validation will be done on hasMemo and showOnlyMemo and are will be used for the memo value on the questions object.

Reading the documentation for the validation plugin I found how I would extend a simple observable .Witch it seems to be done something like this:

ko.validation.rules['mustEqual'] = {
    validator: function (val, otherVal) {
        return val === otherVal;
    },
    message: 'The field must equal {0}'
};

But I do not think this will work for the structure of my viwmodel.How can I create validators for each observable in my observableArrays?

Damien
  • 8,889
  • 3
  • 32
  • 40
aleczandru
  • 5,319
  • 15
  • 62
  • 112
  • 2
    The sample object in your question is not syntactically valid. Please post actual code. Making your fellow developers *guess* what you are working with is highly counter-productive. – Tomalak Jul 31 '13 at 09:21

1 Answers1

1

First off, I agree with Tomalak. Rather than posting a bunch of nonsense that your code "looks something like", you should post some actual code that is readable. For instance, I can't tell if you are using any observable, computed or observableArray members, so I just have to assume that everything is observable or observableArray and there are no computed members.

Now, you said:

The first validation has to be done on each object of the categories array and it will check if hasMemo and memoIsMandatory if this is the case memo will be required.

Let me just say that naming a property hasMemo and that mean that the memo field is required is TERRIBLE! If you call something hasMemo, it should mean that the thing in question has a memo. And why would you need to look at both hasMemo and memoIsMandatory to see if memo is required? Ditto for hasGrade.

Regardless, what you need is just to add validation to each of the observables on your classes. Wait, that's another assumption. You are using classes, right? You're not just creating a single object and giving it a bunch of nested arrays and objects without using constructors, are you? Well I'll proceed assuming that you're creating constructors and leave it at that.

I'll just focus on your first validation because the second one is just like it and the third one is unintelligible to me. So let's say your "CategoriesOnEvaluationDataContract1" object uses the following constructor:

function Category() {
    var self = this;
    self.categoryId = ko.observable();
    self.hasMemo = ko.observable();
    self.memoIsMandatory = ko.observable();
    self.memo = ko.observable();
    //etc etc...
}

You need to extend memo with a validator, in this case you want the required validator. That would look like this:

    self.memo = ko.observable().extend({ required: true });

This makes it so that memo is always required. But that is not what you want, you want it to be required when hasMemo and memoIsMandatory are both true, right?. So this is what you need to do:

    self.memo = ko.observable().extend({ required: { onlyIf: function() {
        return self.hasMemo() && self.memoIsMandatory();
    } } });

There. That's all there is to it. You should be able to figure out the rest. And if not, just let me know. :)

CptRobby
  • 1,441
  • 15
  • 19