JSFiddle - React, Tailwind, and code Playground

by Cristian Trifan

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.2/knockout.validation.js"></script>
<pre data-bind="text: ko.toJSON($rawData.errors, null, 2)"></pre>
<hr />

Email: <input data-bind="value: email"><br>

<!-- ko ifnot: address -->
<button type="button" data-bind="click: addAddress">Add Address</button>
<!-- /ko -->

<div data-bind="with: address">
    Line1: <input data-bind="value: line1"/><br/>
    Line2: <input data-bind="value: line2"/><br/>
    <button type="button" data-bind="click: $parent.removeAddress">Remove Address</button>
</div>

CSS

ul {
    list-style-type: none;
    padding-left: 0;
}

li {
    margin-bottom: 10px
}

input { 
    padding: 4px 6px;
    margin-right: 5px;
}

button {
    padding: 4px 6px;
}

.validationMessage {
    color: #cc0000;
}

.validationElement {
    border: 1px solid #cc0000;
}

pre {
    background-color: #efefef;
    border: 1px solid #ccc;
    padding: 5px 10px;
    border-radius: 3px;
}

JavaScript

ko.validation.init({messagesOnModified: false, decorateInputElement: true, decorateElementOnModified: false}, true);

function AddressViewModel()
{
    this.line1 = ko.observable().extend({required: true});
    this.line2 = ko.observable().extend({required: true});
}

function ViewModel() {
    this.email = ko.observable().extend({required: true, email: true});
    this.address = ko.observable();
    
    this.addAddress = function(viewModel) {
        this.address(new AddressViewModel());

        // The group needs to refresh because the validatables list is now outdated
        ko.contextFor(document.body).$rawData.errors._updateState(this);

    }.bind(this);
    
    this.removeAddress = function() {
        this.address(null);

        // The group needs to refresh because the validatables list is now outdated
        ko.contextFor(document.body).$rawData.errors._updateState(this);
    }.bind(this);
}


ko.applyBindings(ko.validatedObservable(new ViewModel(), {deep: true, observable: true, live: true}));