My input parameter for the code below is just a tablename,
I was able to query the data return in json format, however, i am not able to display my rows item of data. any idea what did i do wrong?
<script>
var invtype = "@ViewBag.invtype";
function ViewModel() {
var self = this;
function ColName(tbstruct){
this.ColumnName = tbstruct.ColumnName
}
self.TBStruct = ko.observableArray();
self.items = ko.observableArray();
self.invtype = invtype;
self.Load = function () {
//expected data for self.items
//[{"$id":"1","Id":2,"Inv_Id":"PV0001-1","ACX_No":"6","ACX_Name":"ABC","S_No":"5", "Acc_Class":"Local","Direction":"Two-Way"},{"$id":"2","Id":2,"Inv_Id":"PV0002-1","ACX_No":"3","ACX_Name":"CKD","S_No":"6", "Acc_Class":"Local","Direction":"Two-Way"}]
$.ajax({
url: "@Url.Content("~/api/")"+self.invtype,
type: 'GET',
dataType: 'JSON',
success: function (data) {
// Map the returned JSON to the View Model
self.items = data;
}
});
//expected data
//[{"$id":"1","ColumnName":"Id","system_type_id":56,"primaryCol":1}, {"$id":"2","ColumnName":"Inv_Id","system_type_id":231,"primaryCol":0},{"$id":"3","ColumnName":"ACX_No","system_type_id":175,"primaryCol":0},{"$id":"4","ColumnName":"ACX_Name","system_type_id":175,"primaryCol":0},{"$id":"5","ColumnName":"S_No","system_type_id":175,"primaryCol":0} {"$id":"27","ColumnName":"Acc_Class","system_type_id":231,"primaryCol":0},{"$id":"28","ColumnName":"Direction","system_type_id":231,"primaryCol":0} ]
$.ajax({
url: "@Url.Content("~/api/inventories/")"+self.invtype,
type: 'GET',
dataType: 'JSON',
success: function (data) {
// Map the returned JSON to the View Model
$.each(data,function(i,dt){
//console.log(dt.ColumnName);
self.TBStruct.push(new ColName(dt));
});
//console.dir(self.TBStruct);
}
});
return self;
};
}
var View = new ViewModel();
ko.applyBindings(View.Load());
here i am trying to display them out.
<thead>
<tr data-bind="foreach: TBStruct">
<th data-bind="text: ColumnName"></th>
</tr>
</thead>
<tbody >
<tr data-bind="foreach: items" >
<td data-bind="text:$data"></td>
</tr>
</tbody>
</table>
function ViewModel() {
var self = this;
self.invtype = "@ViewBag.invtype";
self.columns = ko.observableArray();
self.rows = ko.observableArray();
self.load = function () {
$.when(
$.get("@Url.Content('~/api/inventories/')" + self.invtype),
$.get("@Url.Content('~/api/')" + self.invtype)
)
.then(function (columnResponse, rowResponse) {
var columnDefs = columnResponse[0],
rowDefs = rowResponse[0],
columnMapping = {
key: function (data) {
return ko.utils.unwrapObservable(data.ColumnName);
}
},
rowMapping = {
key: function (data) {
return ko.utils.unwrapObservable(data.Id);
}
};
ko.mapping.fromJS(columnDefs, columnMapping, self.columns);
ko.mapping.fromJS(rowDefs, rowMapping, self.rows);
});
return self;
};
}
Notes:
.when()
and .then()
ensures that view model processing occurs only after both HTML requests have returned successfully. See jQuery's documentation on the topic.key
function in the custom mapping ensures that when you call load()
again then only the appropriate parts of your view model get an update. Otherwise ko.mapping.fromJS
will replace the entire observable, resulting in a complete re-build of the affected part of your page. Specifying key
allows partial page updates, so use a unique property of your data here. (If you don't plan on refreshing data from the server during page life time this step might not be necessary.)ko.utils.unwrapObservable()
is mandatory because during a load operation key
will be used on both the existing view model contents and the server response, so for example data.ColumnName
could be an observable or a raw value.HTML
<table>
<thead>
<tr data-bind="foreach: $root.columns">
<th data-bind="text: ColumnName"></th>
</tr>
</thead>
<tbody data-bind="foreach: $root.rows">
<tr data-bind="foreach: $root.columns">
<td data-bind="text: $parent[ColumnName()]"></td>
</tr>
</tbody>
</table>
Notes:
$root
is actually necessary is in the <tr data-bind="foreach: $root.columns">
binding. The others are just included for consistency.$parent
refers to the row from foreach: $root.rows
.$parent[ColumnName()]
are necessary because ColumnName
is an observable and in a complex binding they are not unwrapped automatically.The whole thing can be seen here: http://jsfiddle.net/Tomalak/A6T8p/
and here (extended version): http://jsfiddle.net/Tomalak/A6T8p/1