我遇到了使用knockout.js绑定来显示有可能从ASP.NET Web Api无效的子对象的问题。
我基本上试图创建一个可搜索的客户列表(使用Jquery Datatable插件),用户将选择一个客户记录来检索客户的完整详细信息(名称,订单历史记录,客户备注等)。此客户详细信息将显示在数据表的一侧,某些字段将是可编辑的。在我的数据模型中,客户可以拥有零个,一个或多个笔记,这就是我遇到问题的对象。
如何重现问题
在用户界面上,如果用户选择带有备注的客户,则敲打绑定并正确显示备注。如果用户选择没有注释的客户,则不显示任何内容(如预期的那样),但是当用户选择另一个带注释的客户时,不会显示任何内容(意外)。
javascript:
$(document).ready(function () {
//Party Model.
var PartyModel = function (id) {
var self = this;
self.loaded = ko.observable(false);
self.party = ko.observableArray([]);
$.getJSON('api/party/GetParty?id=' + id, self.party).done(function () {
self.loaded(true);
});
};
//Customer List Datatable which is displayed on the left.
custlisttable = $('#customerlist').dataTable({
//"bServerSide": true,
"bProcessing": true,
"bPaginate": false,
"sAjaxSource": "api/PartyNameView/GetvPartyNamebyStoreID?storeid=1600", //"api/PartyNameView/GetvPartyName?id=2",
"sAjaxDataProp": "",
"sDom": 'R<"H"lfr>t<"F"iTp>',
"bJQueryUI": true,
"aoColumns": [
{ "mDataProp": "DisplayName" },
{ "mDataProp": "PartyCategoryDesc"}],
"oTableTools": {
"sRowSelect": "single",
"aButtons": [],
"fnRowSelected": function (node) {
aData = custlisttable.fnGetData(node);
$('#displayname').html(aData.DisplayName);
id = aData.PartyID
//get new party model using the PartyID (customerid).
ko.applyBindings(new PartyModel(id));
$("#accordion").show(750);
}
}
});
//Define the Contact Detail Accordian Section, but hide it until a record is selected.
$("#accordion").accordion();
$("#accordion").hide();
$('.accordion .head').click(function () {
$(this).next().toggle();
return false;
}).next().hide();
});
HTML
<h2>Customers</h2>
<div class="row-fluid">
<div class="span8">
<!--Customer List using Datatable-->
<table id="customerlist" class="display">
<thead>
<tr>
<th>Company Name</th>
<th>Customer Type</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="span4">
<div class="row-fluid">
<div id="accordion">
<h3><a href="#"><div id="displayname">[displayname]</div></a></h3>
<div>
<div data-bind="text: party().PartyID"></div>
<div data-bind="text: party().StoreID"></div>
<!--pre data-bind="text: ko.toJSON($data)"></pre-->
</div>
<h3><a href="#">People</a></h3>
<div>
<ul data-bind="foreach: party().People">
<li class="ui-widget" style="list-style-type: none; list-style-position: inside;">
<span data-bind="text: LastName"></span>, <span data-bind="text: FirstName"></span>
</li>
</ul>
</div>
<h3><a href="#">Notes</a></h3>
<div>
<ul data-bind="foreach: party().Notes">
<li class="ui-widget" style="list-style-type: none; list-style-position: inside;">
<span data-bind="text: NoteText"></span>
</li>
<li class="ui-widget" style="list-style-type: none; list-style-position: inside;">
<span data-bind="text: NoteID"></span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
Web API中包含Note对象的示例JSON。
{"$id":"1","PartyID":1,"StoreID":"1600 ","ApprovedforAR":false,"PartyCategoryID":1,"PartyTypeID":1,"OrganizationID":1,"InvoiceHeaders":[],"Notes":[{"$id":"2","NoteID":2,"NoteText":"Test Note 1","PartyID":1,"Party":{"$ref":"1"},"PeopleNotes":[],"EntityKey":{"$id":"3","EntitySetName":"Notes","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"NoteID","Type":"System.Int32","Value":"2"}]}},{"$id":"4","NoteID":3,"NoteText":"Deliveries only after 5","PartyID":1,"Party":{"$ref":"1"},"PeopleNotes":[],"EntityKey":{"$id":"5","EntitySetName":"Notes","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"NoteID","Type":"System.Int32","Value":"3"}]}}],"PartyCategory":{"$id":"6","PartyCategoryID":1,"PartyCategoryDesc":"Category 1","Parties":[{"$ref":"1"}],"EntityKey":{"$id":"7","EntitySetName":"PartyCategories","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyCategoryID","Type":"System.Int32","Value":"1"}]}},"PartyType":{"$id":"8","PartyTypeID":1,"PartyTypeDesc":"Party Type 1","Parties":[{"$ref":"1"},{"$id":"9","PartyID":2,"StoreID":"1600 ","ApprovedforAR":false,"PartyCategoryID":2,"PartyTypeID":1,"InvoiceHeaders":[],"Notes":[],"PartyCategory":{"$id":"10","PartyCategoryID":2,"PartyCategoryDesc":"Category 2","Parties":[{"$ref":"9"}],"EntityKey":{"$id":"11","EntitySetName":"PartyCategories","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyCategoryID","Type":"System.Int32","Value":"2"}]}},"PartyType":{"$ref":"8"},"People":[{"$id":"12","PersonID":2,"FirstName":"Tom","LastName":"Harber","Title":"Accounting","PartyID":2,"Notes":[],"Party":{"$ref":"9"},"EntityKey":{"$id":"13","EntitySetName":"People","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PersonID","Type":"System.Int32","Value":"2"}]}}],"PostalAddresses":[],"ChannelAddresses":[],"EntityKey":{"$id":"14","EntitySetName":"Parties","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyID","Type":"System.Int32","Value":"2"}]}}],"EntityKey":{"$id":"15","EntitySetName":"PartyTypes","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyTypeID","Type":"System.Int32","Value":"1"}]}},"People":[{"$id":"16","PersonID":3,"FirstName":"Jared","LastName":"Kirkwood","Title":"Owner","PartyID":1,"Notes":[],"Party":{"$ref":"1"},"EntityKey":{"$id":"17","EntitySetName":"People","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PersonID","Type":"System.Int32","Value":"3"}]}}],"PostalAddresses":[],"Organization":{"$id":"18","OrganizationID":1,"OrganizationName":"Tony's Pizza Company","TaxExempt":false,"Parties":[{"$ref":"1"}],"EntityKey":{"$id":"19","EntitySetName":"Organizations","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"OrganizationID","Type":"System.Int32","Value":"1"}]}},"ChannelAddresses":[],"EntityKey":{"$id":"20","EntitySetName":"Parties","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyID","Type":"System.Int32","Value":"1"}]}}
Web API中没有注释的示例JSON。
{"$id":"1","PartyID":2,"StoreID":"1600 ","ApprovedforAR":false,"PartyCategoryID":2,"PartyTypeID":1,"InvoiceHeaders":[],"Notes":[],"PartyCategory":{"$id":"2","PartyCategoryID":2,"PartyCategoryDesc":"Category 2","Parties":[{"$ref":"1"}],"EntityKey":{"$id":"3","EntitySetName":"PartyCategories","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyCategoryID","Type":"System.Int32","Value":"2"}]}},"PartyType":{"$id":"4","PartyTypeID":1,"PartyTypeDesc":"Party Type 1","Parties":[{"$ref":"1"},{"$id":"5","PartyID":1,"StoreID":"1600 ","ApprovedforAR":false,"PartyCategoryID":1,"PartyTypeID":1,"OrganizationID":1,"InvoiceHeaders":[],"Notes":[{"$id":"6","NoteID":2,"NoteText":"Hello Party World","PartyID":1,"Party":{"$ref":"5"},"PeopleNotes":[],"EntityKey":{"$id":"7","EntitySetName":"Notes","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"NoteID","Type":"System.Int32","Value":"2"}]}},{"$id":"8","NoteID":3,"NoteText":"It's Tomato Fest","PartyID":1,"Party":{"$ref":"5"},"PeopleNotes":[],"EntityKey":{"$id":"9","EntitySetName":"Notes","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"NoteID","Type":"System.Int32","Value":"3"}]}}],"PartyCategory":{"$id":"10","PartyCategoryID":1,"PartyCategoryDesc":"Category 1","Parties":[{"$ref":"5"}],"EntityKey":{"$id":"11","EntitySetName":"PartyCategories","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyCategoryID","Type":"System.Int32","Value":"1"}]}},"PartyType":{"$ref":"4"},"People":[{"$id":"12","PersonID":3,"FirstName":"Jared","LastName":"Kirkwood","Title":"Owner","PartyID":1,"Notes":[],"Party":{"$ref":"5"},"EntityKey":{"$id":"13","EntitySetName":"People","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PersonID","Type":"System.Int32","Value":"3"}]}}],"PostalAddresses":[],"Organization":{"$id":"14","OrganizationID":1,"OrganizationName":"Tony Tomato's Pizza Company","TaxExempt":false,"Parties":[{"$ref":"5"}],"EntityKey":{"$id":"15","EntitySetName":"Organizations","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"OrganizationID","Type":"System.Int32","Value":"1"}]}},"ChannelAddresses":[],"EntityKey":{"$id":"16","EntitySetName":"Parties","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyID","Type":"System.Int32","Value":"1"}]}}],"EntityKey":{"$id":"17","EntitySetName":"PartyTypes","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyTypeID","Type":"System.Int32","Value":"1"}]}},"People":[{"$id":"18","PersonID":2,"FirstName":"Allen","LastName":"Harber","Title":"Helpdesk","PartyID":2,"Notes":[],"Party":{"$ref":"1"},"EntityKey":{"$id":"19","EntitySetName":"People","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PersonID","Type":"System.Int32","Value":"2"}]}}],"PostalAddresses":[],"ChannelAddresses":[],"EntityKey":{"$id":"20","EntitySetName":"Parties","EntityContainerName":"appCateringFulfillmentEntities","EntityKeyValues":[{"Key":"PartyID","Type":"System.Int32","Value":"2"}]}}
答案 0 :(得分:0)
终于能够搞清楚了。每次用户选择数据表行时,我都在调用applyBindings。根据我发现的一些信息,这是不好的做法。
新视图模型
viewModel = {
Party: ko.observableArray([]),
GetParty: function (id) {
//Reset Party
this.Party([]);
//Retrieve the new data from the server.
$.ajax({ url: "api/party/GetParty?id=" + id,
accepts: "application/json",
cache: false,
statusCode: {
200: function (data) {
viewModel.Party(data);
}
//TODO Handle other status codes
}
});
}
};
ko.applyBindings(viewModel);
然后,当用户单击数据表中的一行时,只需在fnRowSelected函数中调用GetParty。
viewModel.GetParty(id);