How to validate specific child items using Knockout-Validation

213 Views Asked by At

I am using Knockout-Validation's sample and added 2 child collections which contain validation rules.

var Item = function(id, name) {
  var self = this;
  self.id = ko.observable(id).extend({required: {message: 'item id required'}});
  self.name = ko.observable(name).extend(
  {
    minLength: {message :'item name must be at least 5 characters', params: 5}, 
    maxLength: 10
  });
   
   ko.validation.group(self, { live: true }); 
};

var itemsList = [new Item(1, 'test'), new Item(2, 'item 2'), new Item(0, '1')];

var viewModel = {
    items : ko.observableArray(itemsList),
    items2: ko.observableArray(itemsList),
    firstName: ko.observable().extend({minLength: 2, maxLength: 10}),
    lastName: ko.observable().extend({required: true}),
    emailAddress: ko.observable().extend({
        // custom message
        required: {
            message: 'Please supply your email address.'
        }
    }),
    age: ko.observable().extend({min: 1, max: 100}),
    location: ko.observable()
};

Using

ko.validation.group(viewmodel, { deep: true });

my child collections display the validation messages correctly, but I only want 1 child collection validated. The documentation says to pass in the items I want validated like:

ko.validation.group([viewModel.firstName, viewModel.lastName, viewModel.items]);

but when I do that, the child collection no longer displays the validation message.

To reproduce, go to the sample I linked above and click submit. Item 0 and Item 2 in both groups will have validation messages. Change

viewModel.errors = ko.validation.group(viewModel, {deep: true});

to

viewModel.errors = ko.validation.group([viewModel.lastName, viewModel.items]);

Run again and click submit.

enter image description here

1

There are 1 best solutions below

0
Jose Luis On BEST ANSWER

When you create the ViewModel:

 var itemsList = [new Item(1, 'test'), new Item(2, 'item 2'), new Item(0, '1')];
 
 var viewModel = {
     items : ko.observableArray(itemsList),
     items2: ko.observableArray(itemsList),

you are sharing the same observables in the two observable arrays, that is, items and items2.

You could solve it by adding new observables (I add itemsList2 and then I use it to initialize items2):

 var itemsList = [new Item(1, 'test'), new Item(2, 'item 2'), new Item(0, '1')];
 var itemsList2 = [new Item(1, 'test'), new Item(2, 'item 2'), new Item(0, '1')]; <---
 
 var viewModel = {
     items : ko.observableArray(itemsList),
     items2: ko.observableArray(itemsList2), <---
     ...
 };

Finally, you need to add {deep: true} in this sentence:

viewModel.errors = ko.validation.group([viewModel.lastName, viewModel.items], {deep: true});

Here it is a fiddle as an example, and the full ViewModel.

var Item = function(id, name) {
  var self = this;
  self.id = ko.observable(id).extend({required: {message: 'item id required'}});
  self.name = ko.observable(name).extend(
  {
    minLength: {message :'item name must be at least 5 characters', params: 5}, 
    maxLength: 10
  });
   
   ko.validation.group(self, { live: true }); 
};

var itemsList = [new Item(1, 'test'), new Item(2, 'item 2'), new Item(0, '1')];
var itemsList2 = [new Item(1, 'test'), new Item(2, 'item 2'), new Item(0, '1')];

var viewModel = {
    items : ko.observableArray(itemsList),
    items2: ko.observableArray(itemsList2),
    firstName: ko.observable().extend({minLength: 2, maxLength: 10}),
    lastName: ko.observable().extend({required: true}),
    emailAddress: ko.observable().extend({
        // custom message
        required: {
            message: 'Please supply your email address.'
        }
    }),
    age: ko.observable().extend({min: 1, max: 100}),
    location: ko.observable()
};