JSFiddle - React, Tailwind, and code Playground

by aymanfarhat

HTML

<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.js"></script>
<script src="http://knockoutjs.com/js/jquery.validate.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/base/jquery-ui.css">
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<div class='liveExample'> 
    
    <form action='/someServerSideHandler'>
        <p>You have asked for <span data-bind='text: gifts().length'>&nbsp;</span> gift(s)</p>
        <table data-bind='visible: gifts().length > 0'>
            <thead>
                <tr>
                    <th>Gift name</th>
                    <th>Price</th>
                    <th>Date</th>
                    <th />
                </tr>
            </thead>
            <tbody data-bind='foreach: gifts'>
                <tr>
                    <td><input class='required' data-bind='value: name, uniqueName: true' /></td>
                    <td><input class='required number' data-bind='value: price, uniqueName: true' /></td>
                    <td><input class='required' data-bind='datepicker: choosedate,value:choosedate,datepickeroptions: { mindate:  new Date()  }, uniquename: true, minDate: newMinDate ' /></td>
                    <td><a href='#' data-bind='click: $root.removeGift'>Delete</a></td>
                </tr>
            </tbody>
        </table>
     
        <button data-bind='click: addGift'>Add Gift</button>
        <button data-bind='enable: gifts().length > 0' type='submit'>Submit</button>
    </form>
    
</div>

CSS

body { font-family: arial; font-size: 14px; }

.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.liveExample input { font-family: Arial; }
.liveExample b { font-weight: bold; }
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
.liveExample select[multiple] { width: 100%; height: 8em; }
.liveExample h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }

.liveExample table, .liveExample td, .liveExample th { padding: 0.2em; border-width: 0; }
.liveExample td input { width: 13em; }
tr { vertical-align: top; }
.liveExample input.error { border: 1px solid red; background-color: #FDC; }
.liveExample label.error { display: block; color: Red; font-size: 0.8em; } 
.liveExample th { font-weight: bold; }

li { list-style-type: disc; margin-left: 20px; }

JavaScript

debugger;
var GiftModel = function(gifts) {
    var self = this;

    var d = ko.mapping.fromJS(gifts);
    self.gifts = d;

    self.updateMinDates = function() {
        self.gifts()[0].newMinDate( new Date());
        for (var i = 1; i < self.gifts().length; i++) {
            self.gifts()[i].newMinDate(self.gifts()[i - 1].choosedate);
        }
    }

    // create newMinDate properties
    for (var i = 0; i < gifts.length; i++) {
        self.gifts()[i].newMinDate = ko.observable(new Date());
    }
    self.updateMinDates();

    self.addGift = function() {
        self.gifts.push({
            name: ko.observable(""),
            choosedate: ko.observable(""),
                price: ko.observable(""),
            newMinDate: ko.observable(new Date())
        });
        self.updateMinDates();
    };

    self.removeGift = function(gift) {
        self.gifts.remove(gift);
        self.updateMinDates();
    };
    self.save = function(form) {
        alert("Could now transmit to server: " + ko.utils.stringifyJson(self.gifts));
        // To actually transmit to server as a regular form post, write this: ko.utils.postJson($("form")[0], self.gifts);
    };
};

ko.bindingHandlers.minDate = {

    update: function(element, valueAccessor) {

        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
        if(ko.isObservable(valueUnwrapped))  valueUnwrapped = valueUnwrapped();      
        if(valueUnwrapped  == "") return;
               
        var elemt = $(element);

        elemt.datepicker("option", "minDate", valueUnwrapped);
    }

}

ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        //initialize datepicker with some optional options
        var options = allBindingsAccessor().datepickerOptions || {};
        $(element).datepicker(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function() {
           ...