Using knockout js here:
Following on from my post at Knockout JS: Creating dynamic table columns
I have managed to somehow create dynamic columns in knockout. So when the user clicks add row it adds a row to the table. What I am currently stuck is at how to get the data with what is entered in the textboxes in my table. Say for ex I have 4 columns and adding a row would create 4 textbox in the table. When the user enters the data in those textbox I want to loop and get all the data that is entered and save.
Here is the jsfiddle that I have managed to create.
https://jsfiddle.net/aman1981/L3pjhk0z/6/
My valuesData is always empty here:
"valuesData": [
{}
What updates do I need to make in my fiddle to get all the data. May be in the json form as
{
"col1": "1",
"col2": "2"
....and so on depending on the columns
}
Let me know if you need more information
Your input fields didn't map to your value data.
My code differs in some points of yours. To ensure, that self.columnNames
does not have more columns than ValuesData
I created a static object ValuesData.columns
which contains all relevant column definitions. The observables for the single columns are created dynamically as soon as you click on addRow
.
(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();
})();
<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>
</table>
<br><br>
<div class="col-xs-12 col-sm-6">
<input type="button" value="Add Row" class="btn btn-primary" data-bind="click: addRow" />
<input type="button" value="Save" class="btn btn-primary" data-bind="click: Save" />
</div>
<pre data-bind="text: ko.toJSON(valuesData, null, 2)"></pre>