问题
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>
回答1:
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:
- Using jQuery's
.when()
and.then()
ensures that view model processing occurs only after both HTML requests have returned successfully. See jQuery's documentation on the topic. - The
key
function in the custom mapping ensures that when you callload()
again then only the appropriate parts of your view model get an update. Otherwiseko.mapping.fromJS
will replace the entire observable, resulting in a complete re-build of the affected part of your page. Specifyingkey
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.) - The use of
ko.utils.unwrapObservable()
is mandatory because during a load operationkey
will be used on both the existing view model contents and the server response, so for exampledata.ColumnName
could be an observable or a raw value. - Be sure to read through the advanced section of the mapping plugin documentation, you might find other helpful bits.
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:
- The only place where
$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 fromforeach: $root.rows
.- The parentheses in
$parent[ColumnName()]
are necessary becauseColumnName
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
回答2:
rewrote my self.load
self.Load = function () {
$.ajax({
url: "@Url.Content("~/api/")"+self.invtype,
type: 'GET',
dataType: 'JSON',
success: function (data) {
// Map the returned JSON to the View Model
ko.mapping.fromJS(data,{}, self.items);
}
});
$.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){
self.TBStruct.push(new ColName(dt));
});
}
});
return self;
};
output with iteration below
<thead>
<tr data-bind="foreach: TBStruct">
<th data-bind="text: HeaderName,visible: SystemField == -1 || Visible" ></th>
</tr>
</thead>
<tbody data-bind="foreach: items " >
<tr data-bind="foreach: $root.TBStruct, click:function() { alert('me');}" id="rowData">
<td data-bind="text: $parent[ColumnName],visible: SystemField == -1 || Visible" ">
</td>
</tr>
</tbody>
来源:https://stackoverflow.com/questions/16342767/dynamic-column-and-rows-with-knockoutjs