JSFiddle - React, Tailwind, and code Playground

by idavidcastellanos

HTML

<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/1.0.2/knockout.validation.min.js"></script>
<table data-bind="visible: jointholders().length > 0">
    <thead>
        <tr>
            <th>Title</th>
            <th>Other title</th>
            <th>Forename</th>
            <th>Surname</th>
            <th></th>
        </tr>
    </thead>
    <tbody data-bind="foreach: jointholders">
        <tr>
            <td>
                <select data-bind="options: $parent.titles, value: title, optionsText: 'title', optionsValue: 'title', optionsCaption: 'Select...'"></select></td>
            <td>
                <input type="text" data-bind="enable: title() === 'Other', value: otherTitle, valueUpdate: 'afterkeydown'" /></td>
            <td>
                <input type="text" data-bind="value: forename, valueUpdate: 'afterkeydown', validationElement: forename" />
            </td>
            <td>
                <input type="text" data-bind="value: surname, valueUpdate: 'afterkeydown'" /></td>
            <td>
                <button data-bind="click: $parent.removeJointHolder">Remove</button></td>
        </tr>
    </tbody>
</table>

<pre name="taJointHolders" style="width: 50%" rows="5" data-bind="text: ko.toJSON(jointholders)"></pre><br />
<button data-bind="click: addJointHolder, enable: jointholders().length < 5">Add Joint Holder</button>
<div data-bind="foreach:AllErrors">
    JointHolder:
    <div data-bind="foreach:Errors">
        <span data-bind="text:Property" ></span>:
        <span data-bind="text:Error" ></span><br />
    </div>
</div>
<script type="text/html" id="vmTemplate">
    <span class="alert" data-bind="if: field.isModified() && !field.isValid(),
    attr: { title: field.error }">*</span>
</script>

CSS

.alert {
            color: red;
        }

JavaScript

$(function () {
        var my = my || {};
       
        my.JointHolder = function () {
            var self = this;
            self.title = ko.observable(null).extend({
                required: {message: 'This is a required field.'}
            });
            self.otherTitle = ko.observable(null).extend({
                required:  {
                    onlyIf: function () {
                        return self.title() == "Other";
                    },
                    message: 'This is a required field.'
                },
                maxLength: 20,
                pattern: {
                    message: 'This field must only contain letters and numbers.',
                    params: '^[a-zA-Z0-9]+$'
                }
            });
            self.forename = ko.observable(null).extend({
                required: true,
                maxLength: 70,
                pattern: {
                    message: 'This field must only contain letters and numbers.',
                    params: '^[a-zA-Z0-9]+$'
                }
            });
            self.surname = ko.observable(null).extend({
                required: true,
                maxLength: 40,
                pattern: {
                    message: 'This field must only contain letters and numbers.',
                    params: '^[a-zA-Z0-9]+$'
                }
            });
            self.Errors = ko.computed(function() {
                var errs = [];
                for(var p in self) {
                    if(self.hasOwnProperty(p)) {
                        var pObj = self[p];
                       console.info("validating");
                        if(!!!ko.validation.utils.isValidatable(self[p])) {
                            console.info("ope, nvm");
                        } else {                            
                            if(!ko.validation.validateObservable(pObj)) {
                               ...