JSFiddle - React, Tailwind, and code Playground
by jlspake
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<div>
<table id="tblPossessionChanges">
<thead>
<tr>
<th><a href="#" class="buttonSmall" data-bind="click: addPossessionChange">Add</a></th>
<th>From</th>
<th>To</th>
</tr>
</thead>
<tbody data-bind="foreach: PossessionChanges">
<tr>
<td class="prompt">
<a href="#" class="buttonSmall" data-bind="click: $root.removePossessionChange">Delete</a> </td>
<td>
<select class="form-control"
data-bind="options: $root.AvailableFrom,
value: SelectedFrom,
optionsText: function(i) {return i.Name},
optionsValue: function(i) {return i.ID},
optionsCaption: 'Please select a Person...',
optionsAfterRender: $root.setOptionDisable,
select2: { placeholder: 'Please select a Person...', allowClear: false}">
</select>
</td>
<td>
<select class="form-control"
data-bind="options: $root.AvailableTo,
value: SelectedTo,
optionsText: function(i) {return i.Name},
optionsValue: function(i) {return i.ID},
optionsCaption: 'Please select a Person...',
optionsAfterRender: $root.setOptionDisable,
select2: { placeholder: 'Please select a Person...', allowClear: false}">
...
CSS
#tblPossessionChanges {
width: 70%;
height: 100px;
text-align: center;
table-layout: fixed;
}
#tblPossessionChanges td,
#tblPossessionChanges th {
padding: 1rem;
}
#tblPossessionChanges thead th {
text-align: center;
}
#tblPossessionChanges thead th:first-child {
text-align: left;
width: 10%;
}
#tblPossessionChanges tbody td:first-child {
text-align: left;
width: 10%;
}
#tblPossessionChanges>tbody>tr>td.prompt>a {
font-weight: bold;
}
#tblPossessionChanges tbody td select {
width: 75%
}
JavaScript
ko.bindingHandlers.select2 = {
init: function(element, valueAccessor, allBindingsAccessor, bindingContext) {
ko.utils.domNodeDisposal.addDisposeCallback(element,
function() {
$(element).select2('destroy');
});
var select2 = ko.utils.unwrapObservable(allBindingsAccessor().select2);
$(element).select2(select2);
},
update: function(element, valueAccessor, allBindingsAccessor, bindingContext) {
var allBindings = allBindingsAccessor();
if ("value" in allBindings) {
if ((allBindings.select2.multiple || element.multiple) && allBindings.value().constructor != Array) {
$(element).val(allBindings.value().split(',')).trigger('change');
} else {
$(element).val(allBindings.value()).trigger('change');
}
}
$(element).trigger("change");
}
};
function BookPossessionTransferVM() {
var self = this;
self.AllFromList = ([{ "IsAdult": false, "Name": "Bob", "ID": 38438 }, { "IsAdult": false, "Name": "Gordon", "ID": 54686 }, { "IsAdult": true, "Name": "Bill", "ID": 45645 }, { "IsAdult": false, "Name": "Sue", "ID": 1231 }, { "IsAdult": false, "Name": "Ling", "ID": 123578 }, { "IsAdult": false, "Name": "Ivy", "ID": 78945 }]);
self.AllToList = ([{ "IsAdult": false, "Name": "Adam", "ID": 38438 }, { "IsAdult": false, "Name": "Geoff", "ID": 54686 }, { "IsAdult": true, "Name": "Josh", "ID": 45645 }, { "IsAdult": false, "Name": "Sam", "ID": 1231 }, { "IsAdult": false, "Name": "Ming", "ID": 123578 }, { "IsAdult": false, "Name": "Austin", "ID": 78945 }, { "IsAdult": false, "Name": "Tsz", "ID": 78945 }, { "IsAdult": true, "Name": "Ireylnn", "ID": 78945 }, { "IsAdult": true, "Name": "Isabelle", "ID": 78945 }, { "IsAdult": true, "Name": "Vickey", "ID": 78945 }]);
self.PossessionChanges = ko.observableArray([]);
self.PossessionChanges.push(new PossessionChangeVM(self.PossessionChanges().length + 1));
self.GetPersonById = function(id) {
return ko.utils.arrayFirst(self.AllFromList,...