Search code examples
knockout.jsknockout-2.0knockout-validation

knockout.js validation on observableArray to require all items (no empty fields)


I have written the following example of using knockout.

HTML

<script id="customMessageTemplate" type="text/html">
    <em class="customMessage" data-bind='validationMessage: field'></em>
</script>
<fieldset>
    <legend>User: <span data-bind='text: errors().length'></span> errors</legend>
    <label>First name: <input data-bind='value: firstName'/></label>
    <label>Last name: <input data-bind='value: lastName'/></label>    

    <table>
    <thead>
        <tr><th>Value</th></tr>
    </thead>
    <tbody data-bind="foreach: captcha">
        <tr>
            <td><input data-bind="value: value" type="test" /></td>
        </tr>
    </tbody>
</table>

<button type="button" data-bind='click: submit'>Submit</button>

Knockout

ko.validation.rules.pattern.message = 'Invalid.';


ko.validation.configure({
    registerExtenders: true,
    messagesOnModified: true,
    insertMessages: true,
    parseInputAttributes: true,
    messageTemplate: null
});


var captcha = function (val) {
    return val == 11;
};

var mustEqual = function (val, other) {
    return val == other();
};

var viewModel = {
    firstName: ko.observable().extend({ required: true }),
    lastName: ko.observable().extend({ required: true }),
    captcha: ko.observableArray([{value: "test"}]),


    submit: function () {
        if (viewModel.errors().length == 0) {
            alert('Thank you.');
        } else {
            alert('Please check your submission.');
            viewModel.errors.showAllMessages();
        }
    }
};


viewModel.errors = ko.validation.group(viewModel);

ko.applyBindings(viewModel);

What should I add to observableArray to require all items in this array the same way like usual observable object reffrering to input fields FirstName and LastName in presented example?


Solution

  • I'm not sure if this is what you are expecting. If you want to add validation to each object of an observableArray, you can do something like this:

    Create a captchaViewModel function and add the required validation to the value property

    var captchaViewModel = function(val) {
      this.value = ko.observable(val).extend({
        required: true
      });
     // other properties if any
    }
    

    Then change your viewModel to:

    var viewModel = {
      firstName: ko.observable().extend({ required: true }),
      lastName: ko.observable().extend({ required: true }),
      captcha: ko.observableArray([new captchaViewModel("test")]),
    
      submit: function() {
        if (viewModel.errors().length == 0) {
          alert('Thank you.');
        } else {
          alert('Please check your submission.');
          viewModel.errors.showAllMessages();
        }
      }
    };
    

    You also need to add grouping property to the configuration and set deep: true.

    ko.validation.configure({
       .......
       .......
      // "deep" indicates whether to walk the ViewModel (or object) recursively, 
      // or only walk first-level properties
      grouping: { deep: true }
    });
    

    Here's a fiddle for testing