JSFiddle - React, Tailwind, and code Playground
HTML
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="//rawgit.com/RobinHerbots/jquery.inputmask/3.x/dist/jquery.inputmask.bundle.js"></script>
<table class="table table-condensed table-hover table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach:numbers">
<tr>
<td><span data-bind="text:name"></span>
</td>
<td><span data-bind="text:phone"></span>
</td>
<td class="form-group">
<button class="btn btn-sm btnRemove btn-default" type="button" data-bind="click:$root.removeNumber"> <i class="fa fa-trash"></i>
</button>
</td>
</tr>
</tbody>
<tfoot data-bind="with:newNumber">
<tr>
<td>
<input type="text" class="input-sm form-control" data-bind="textInput:name" />
</td>
<td>
<input type="text" class="input-sm form-control" data-mask="phone" data-bind="textInput:phone" />
</td>
<td>
<button class="btn btn-sm btn-default" id="btnAdd" type="button" data-bind="click:$root.addNewNumber"><i class="fa fa-plus"></i>
</button>
</td>
</tr>
</tfoot>
</table>
<h2>Values</h2>
<p>Numbers: <span data-bind="text:numbersJson"></span>
</p>
<p>New Number: <span data-bind="text:newNumberJson"></span>
</p>
JavaScript
(function () {
var PhoneNumber = function () {
this.name = ko.observable();
this.phone = ko.observable();
};
function setMask() {
$('[data-mask="phone"]').inputmask({
mask: '(999)999-9999'
});
}
var vm = {
newNumber: ko.observable(new PhoneNumber()),
numbers: ko.observableArray([]),
};
console.log('vm', vm.numbers());
setMask();
vm.numbersJson = ko.computed(function () {
return ko.toJSON(vm.numbers);
});
vm.newNumberJson = ko.computed(function () {
return ko.toJSON(vm.newNumber);
});
//events
vm.addNewNumber = function () {
vm.numbers.push(vm.newNumber());
vm.newNumber(new PhoneNumber());
setTimeout(setMask, 0);
};
vm.removeNumber = function (data) {
vm.numbers.remove(data);
};
ko.applyBindings(vm);
/*
$(document).on('click', '#btnAdd', addNewNumber);
$(document).on('click', '.btnRemove', removeNumber);
*/
})();