Using Knockout JS:
I have a requirement as.
I have a table with 2 static columns where each has a text-box. I also have a add row button outside the table an
I was able to resolve this using the post at: Knockout JS: Get Textbox data from Table under for-each binding
Here is my code:
(function() {
var ViewModel = function() {
var self = this;
self.valuesData = ko.observableArray();
self.columns = ko.computed(function() {
if (self.valuesData().length === 0)
return [];
return ValuesData.columns;
});
self.addRow = function() {
self.valuesData.push(new ValuesData());
};
self.Save = function() {
alert('Data:')
};
self.removeRow = function(data) {
self.valuesData.remove(data);
};
}
// Dynamic values.
var ValuesData = function(siid, comment) {
var self = this;
// Add observables dynamically for all relevant columns.
for (var i = 0; i < ValuesData.columns.length; i++) {
var column = ValuesData.columns[i];
self[column.Property] = ko.observable(column.InitialValue)
}
};
// Basic column definition.
ValuesData.columns = [{
Caption: 'SIID',
Property: 'SIID',
InitialValue: undefined
},
{
Caption: 'Column 1',
Property: 'Col1',
InitialValue: undefined
},
{
Caption: 'Column 2',
Property: 'Col2',
InitialValue: 'banana'
},
{
Caption: 'Comment',
Property: 'Comment',
InitialValue: undefined
}
]
vm = new ViewModel()
ko.applyBindings(vm);
// add initial row.
vm.addRow();
})();
Here is the html part:
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-
min.js"></script>
<br><br>
<table>
<thead>
<!-- NEW: use ko foreach with 'as' to have an alias for accessing $data. -->
<tr data-bind="foreach: { data: columns, as: 'column'}">
<th> <span data-bind="text: column.Caption"></span>
</th>
</tr>
</thead>
<tbody data-bind="foreach: { data: valuesData, as: 'rowData'}">
<tr data-bind="foreach: { data: $parent.columns, as: 'column' }">
<!-- NEW: bind to the corresponding property/observable in ValuesData -->
<td><input type="text" class="form-control textbox" data-bind="textInput:
rowData[column.Property]" /> </td>
</tr>
<tr>
<td>
<input type="button" value="Remove Row" data-bind="click:
$parent.removeRow" class="btn btn-danger" />
</td>
</tr>
</tbody>
Nice for you i have a dynamic table component from my previous project:
var observable = ko.observable;
var pureComputed = ko.pureComputed;
var observableArray = ko.observableArray;
var unwrap = ko.unwrap;
var data = observableArray([{
a: 123,
b: 234,
c: 345
},{
a: 1231,
b: 2341,
c: 3451
},{
a: 1232,
b: 2342,
c: 3425
},{
a: 1233,
b: 2343,
c: 3453
}]);
var columns = observableArray([{
field: "a",
displayName: "A"
},{
field: "b",
displayName: "B (i can even change the title)"
}])
function viewModel(params) {
var paramColumns = params.columns;
var paramData = params.data;
var paramFieldKey = params.fieldKey || "field";
var paramDisplayNameKey = params.displayNameKey || "displayName";
var koColumnHeaders = pureComputed(function () {
var columns = paramColumns();
var columnHeaders = [];
var fieldKey = unwrap(paramFieldKey);
var displayNameKey = unwrap(paramDisplayNameKey);
for (var i in columns) {
var column = columns[i];
columnHeaders.push({
field: column[fieldKey],
displayName: column[displayNameKey]
})
}
return columnHeaders;
})
var koRows = pureComputed(function () {
var data = paramData();
var columns = paramColumns();
var fieldKey = unwrap(paramFieldKey);
var rows = [];
for (var i in data) {
var datum = data[i];
var cells = []
var row = {
entity: data,
cells: cells
};
for (var j in columns) {
var column = columns[j];
cells.push(datum[column[fieldKey]] || "");
}
rows.push(row);
}
return rows;
});
return {
rows: koRows,
columns: koColumnHeaders,
}
}
ko.applyBindings(new viewModel({
data: data,
columns: columns
}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table table-bordered" border="1">
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: displayName">
</th>
</tr>
</thead>
<tbody data-bind="foreach: rows">
<tr>
<!-- ko foreach: cells -->
<td class="" data-bind="text: $data"></td>
<!-- /ko -->
</tr>
</tbody>
</table>