JSFiddle - React, Tailwind, and code Playground

by jearles

HTML

<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-2.2.0.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"></script>
<script src="http://www.eyecon.ro/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
    <div class="well">
        <h3>Project Name
        </h3>
        <input type="text" name="txtProjectName" placeholder="Project Name" data-bind='value: ProjectName, valueUpdate: "afterkeydown"' />
        <div class="alert alert-error" id="alertProjectName" data-bind='visible: ProjectName.hasError, text: ProjectName.validationMessage'>
        </div>


    </div>
    <div class="well">
        <h3>Project Timeline
        </h3>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>Start Date</th>
                    <th>End date</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>
                        <input data-bind="datepicker: ProjectStartDate, datepickerOptions: { startDate: new Date() }" />
                    </td>
                    <td>
                        <input data-bind="datepicker: ProjectEndDate, datepickerOptions: { startDate: new Date() }" />
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
    <div class="well">
        <h3>Project Description
        </h3>
        <textarea id="ProjectDetails" data-bind='value: ProjectDescription, valueUpdate: "afterkeydown"' placeholder="Enter Project Details ..."></textarea>
        <div class="alert alert-error" id="alertProjectDescription" data-bind='visible: ProjectDescription.hasError, text: ProjectDescription.validationMessage'>
        </div>
    </div>
    <div>
       ...

CSS

@import url('http://twitter.github.com/bootstrap/assets/css/bootstrap.css');
@import url('http://www.eyecon.ro/bootstrap-datepicker/css/datepicker.css');

JavaScript

ko.bindingHandlers.datepicker = {
            init: function (element, valueAccessor, allBindingsAccessor) {
                //initialize datepicker with some optional options
                var options = allBindingsAccessor().datepickerOptions || {};
                $(element).datepicker(options).on("changeDate", function (ev) {
                    var observable = valueAccessor();
                    observable(ev.date);
                });
            },
            update: function (element, valueAccessor) {
                var value = ko.utils.unwrapObservable(valueAccessor());
                $(element).datepicker("setValue", value);
            }
        };

        ko.extenders.required = function (target, overrideMessage) {
            //add some sub-observables to our observable
            target.hasError = ko.observable();
            target.validationMessage = ko.observable();

            //define a function to do validation
            function validate(newValue) {
                target.hasError(newValue ? false : true);
                target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
            }

            //initial validation
            validate(target());

            //validate whenever the value changes
            target.subscribe(validate);

            //return the original observable
            return target;
        };

        var ProjectViewModel = {
            ProjectName: ko.observable("").extend({ required: "" }),
            ProjectDescription: ko.observable("").extend({ required: "" }),
            ProjectStartDate: ko.observable(new Date("09/01/2011")).extend({ required: "" }),
            ProjectEndDate:  ko.observable(new Date("09/01/2011")).extend({ required: "" })
         };

        $(document).ready(function () {
            ko.applyBindings(ProjectViewModel);
        });