JSFiddle - React, Tailwind, and code Playground

by origineil

HTML

<script src="https://rawgit.com/ericmbarnard/Knockout-Validation/master/Src/knockout.validation.js"></script>
<div class="form-group">
    <table id="items">
        <thead>
            <tr>
                <th>Item Description</th>
                <th>Brand</th>
                <th>Quantity</th>
                <th>Unit of Measure</th>
                <th>Special Instructions</th>
                <th></th>
            </tr>
        </thead>
        <tbody data-bind="foreach: orderItems">
            <tr>
                <td>
                    <input data-bind="value: itemName" class="form-control" />
                </td>
                <td>
                    <input data-bind="value: brand" class="form-control" />
                </td>
                <td>
                    <input data-bind="value: quantity" class="form-control" />
                </td>
                <td>
                    <select data-bind="options: $root.measurementOptions, value: measurement, optionsText: 'name'" class="form-control" />
                </td>
                <td>
                    <input data-bind="value: instructions" class="form-control" />
                </td>
                <td>
                    <button data-bind="click: $root.removeOrderItem" class="form-control">Remove</button>
                </td>
            </tr>
        </tbody>
    </table>
</div>
<div class="form-group">
    <button data-bind="click: $root.addOrderItem" class="form-control">Add Another Item</button>
</div>
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <button data-bind="click: $root.save" class="btn btn-default">Submit Order</button>
    </div>
</div>

<div data-bind='text: ko.toJSON($data)'></div>

JavaScript

function OrderItem(itemName, brand, quantity, instructions, measurement) {
     var self = this;

     self.itemName = ko.observable(itemName);
     self.brand = ko.observable(brand);
     self.quantity = ko.observable(quantity);
     self.instructions = ko.observable(instructions);
     self.measurement = ko.observable(measurement);
 }

 function OrderViewModel() {

     var self = this;

     self.firstName = ko.observable().extend({
         required: true
     });
     self.lastName = ko.observable().extend({
         required: true
     });
     self.telephone = ko.observable().extend({
         required: {
             message: 'This field is required'
         },
         pattern: {
             params: '^[0-9]{3}.[0-9]{3}.[0-9]{4}$',
             message: 'Format: 999-999-9999'
         }
     });
     self.address1 = ko.observable().extend({
         required: true
     });
     self.address2 = ko.observable();
     self.city = ko.observable("Lexington");
     self.state = ko.observable("KY");
     self.zipcode = ko.observable('').extend({
         required: true,
         minLength: 5,
         maxLength: 5,
         number: true
     });
     self.specialinstructions = ko.observable();
     self.desireddeliverytime = ko.observable();

     self.orderItems = ko.observableArray([
     new OrderItem("", "", 1, "", {
         id: 0,
         name: "Qty"
     })]);

     self.removeOrderItem = function (orderItem) {
         self.orderItems.remove(orderItem);
     }

     self.addOrderItem = function (orderItem) {
         self.orderItems.push(new OrderItem("", "", 1, "", {
             id: 0,
             name: "Qty"
         }));
     }

     self.save = function () {
         if (self.isValid()) {

             alert("Thank you for your order!");
            
         } else {
             self.errors.showAllMessages();
         }
     }
 }

 var viewModel = ko.validatedObservable(new OrderViewModel());
 
 ko.applyBindings(viewModel);