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'> </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() {
...