JSFiddle - React, Tailwind, and code Playground

by nsilberstein

HTML

<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout-validation/1.0.2/knockout.validation.min.js"></script>
<div id="step2" data-bind="with: ContactInfoViewModel">
    <h3>Enter Contact Information</h3>
    <p>Fill me out first.</p>
    <form id="ContactForm">
        <div>
            <label for="Contact_FirstName">First Name</label>
            <input type="text" id="Contact_FirstName" name="FirstName" data-bind="value: firstName" />
        </div>
        <div>
            <label for="Contact_LastName">Last Name</label>
            <input type="text" id="Contact_LastName" name="LastName" data-bind="value: lastName" />
        </div>
        <div>
            <label for="Contact_Address">Address</label>
            <input type="text" id="Contact_Address" name="Address" data-bind="value: address" />
        </div>
    </form>
    <button data-bind="click: validateContact">Validate Contact</button>
</div>

<div id="step3" data-bind="with: BillingInfoViewModel">
    <h3>Enter Billing Information</h3>
    <p>Fill me out second.  Try checking the box below.</p>
    <label for="CopyContact">Same as Contact Information</label>
    <input id="CopyContact" type="checkbox" data-bind="click: copyContact" />
    <br/>
    <br/>
    <form id="BillingForm">
        <div>
            <label for="Billing_FirstName">First Name</label>
            <input type="text" id="Billing_FirstName" name="FirstName" data-bind="value: firstName" />
        </div>
        <div>
            <label for="Billing_LastName">Last Name</label>
            <input type="text" id="Billing_LastName" name="LastName" data-bind="value: lastName" />
        </div>
        <div>
            <label for="Billing_Address">Address</label>
            <input type="text" id="Billing_Address" name="Address" data-bind="value: address" />
        </div>
    </form>
    <button data-bind="click: validateBilling">Validate...

JavaScript

ko.validation.init();

function ContactInfoViewModel() {
    var self = this;

    self.errors = ko.validation.group(this, {
        deep: true,
        observable: false
    });

    self.firstName = ko.observable().extend({
        required: true
    });
    self.lastName = ko.observable().extend({
        required: true
    });
    self.address = ko.observable().extend({
        required: true
    });
    
    self.validateContact = function () {
        self.errors.showAllMessages();
        if (self.errors().length == 0) {
            alert("No contact validation errors.");
        }
    };
}

function BillingInfoViewModel() {
    var self = this;

    self.errors = ko.validation.group(this, {
        deep: true,
        observable: false
    });

    self.firstName = ko.observable().extend({
        required: true
    });
    self.lastName = ko.observable().extend({
        required: true
    });
    self.address = ko.observable().extend({
        required: true
    });

    self.copyContact = function () {
        copyContactToBilling();
        return true;
    };
    
    self.validateBilling = function () {
        self.errors.showAllMessages();
        if (self.errors().length == 0) {
            alert("No billing validation errors.");
        }
    };
}

function PageViewModel() {
    self.ContactInfoViewModel = new ContactInfoViewModel();
    self.BillingInfoViewModel = new BillingInfoViewModel();
}

ko.applyBindings(new PageViewModel());


function copyContactToBilling() {
    var contactForm = $("#ContactForm");
    var billingForm = $("#BillingForm");
    if ($("#CopyContact").is(":checked")) {
        $(":input[name]", contactForm).each(function () {
            $("[name=" + $(this).attr("name") + "]", billingForm).val($(this).val());
        });
    } else {
        $(":input[name]", billingForm).each(function () {
            $(this).val("");
            $(this).removeAttr("disabled");
        });
    }
}