我是Knockout的新手,我正在构建一个简单的POC来使用knockout来构建SPA(单页应用程序)。
我想要做的是在应用程序加载时显示“业务单位”,并且在选择业务单位时显示该业务单位下的所有“前端单位”以及选择前端单元时,显示所有“销售额”细分“在该前端单元下。
所有这些都将在使用相同视图的单个页面中发生,并且viewmodel将基于所选业务单位或前端单元绑定模型。
我面临的问题是,我有5个业务单位首先在文档准备就绪上正确绑定,但在选择业务单位时,前端单元每次重复5次。在这种情况下,我有2个前端单元,每个都显示5次。选择前端单元的问题相同。
您可以在以下jsFiddle示例中模仿此问题 - jsFiddle Link
如果您无法访问jsfiddle链接,请告诉我。在这个示例中,我使用了数组,但实际上我将通过异步调用获取数据到oData服务。
这是视图HTML:
<div id="divbu">
<h4 data-bind="text: Heading"></h4>
<ul data-role="listview" data-inset="true" data-bind="foreach: Collection">
<li data-role="list-divider" data-bind="text: EntityName"></li>
<li>
<a href="#" data-bind="click: $root.fnNextLevel">
<table border="0">
<tr>
<td>
<label style="font-size: 12px;">Bus. Plan: </label>
</td>
<td>
<label style="font-size: 12px;" data-bind="text: BusinessPlan"></label>
</td>
<td>
<label style="font-size: 12px;">Forecast: </label>
</td>
<td>
<label style="font-size: 12px;" data-bind="text: Forecast"></label>
</td>
</tr>
<tr>
<td>
<label style="font-size: 12px;">Gross Sales: </label>
</td>
<td colspan="3">
<label style="font-size: 12px;" data-bind="text: GrossSales"></label>
</td>
</tr>
</table>
</a>
</li>
</ul>
</div>
这是模型和视图模型:
function CommonModel(model, viewType) {
var self = this;
if (viewType == 'BU') {
self.EntityName = model[0];
self.BusinessUnit = model[0];
self.BusinessPlan = model[1];
self.Forecast = model[2];
self.GrossSales = model[3];
} else if (viewType == 'FEU') {
self.EntityName = model[1];
self.BusinessUnit = model[0];
self.FrontEndUnit = model[1];
self.BusinessPlan = model[2];
self.Forecast = model[3];
self.GrossSales = model[4];
} else if (viewType == 'SS') {
self.EntityName = model[2];
self.BusinessPlan = model[3];
self.Forecast = model[4];
self.GrossSales = model[5];
}
}
function ShipmentReportsViewModel(results, viewType) {
var self = this;
self.Collection = ko.observableArray([]);
for (var i = 0; i < results.length; i++) {
self.Collection.push(new CommonModel(results[i], viewType));
}
if (viewType == 'BU') {
self.Heading = "Business Units";
self.fnNextLevel = function (businessUnit) {
FetchFrontEndUnits(businessUnit);
};
self.Home = function () {
FetchBusinessUnits();
};
} else if (viewType == 'FEU') {
self.Heading = results[0][0];
self.fnNextLevel = function (frontEndUnit) {
FetchSalesSegments(frontEndUnit);
};
self.Home = function () {
FetchBusinessUnits();
};
} else if (viewType == 'SS') {
self.fnNextLevel = function () {
alert('No activity zone');
};
self.Heading = results[0][0] + ' - ' + results[0][1];
self.Home = function () {
FetchBusinessUnits();
};
}
}
您可以在jsFiddle链接中看到完整的代码。
我还尝试了多个视图和多个视图模型,我通过给出元素ID来应用绑定。在这种情况下,来自业务部门的一个流程 - &gt;销售细分很好,但当我点击主页或后退按钮并再次绑定到该元素时,我面临同样的问题。 (在jsFiddle示例中没有完成主页和后退按钮功能。)
如果需要更多详细信息,请与我们联系。我确实在堆栈溢出中查看了很多其他链接,但没有解决这个特定问题。
非常感谢任何帮助。提前谢谢。
答案 0 :(得分:3)
这里的问题是你调用你的ko.applybindings TWICE并且有一个foreach绑定在5个项目内迭代,因此数据被重复五次。
你不应该在同一个型号上多次调用ko.applybindings。 即使参数化,您的模型也始终相同。
我在这里遇到了同样的问题:Data coming from an ObservableArray are displayed twice in my table
您在viewModel中拥有业务逻辑的事实是可以讨论的事情,并且这使得解决这个问题变得不容易。
制作3个类,将它们放在一个没有逻辑的普通模型中。一旦你应用了ko.applyBindings一次,你就必须像这样修改数组:
viewModel.myArray(newValues)
以下是修改过的代码的小提琴:http://jsfiddle.net/MaurizioPiccini/5B9Fd/17/ 它不是exaclty你需要的东西但是如果通过将Collection对象范围移到模型之外来删除多个绑定。 你可以看到问题是你在同一个模型上两次调用ko.applybindings。
答案 1 :(得分:0)
最后,我得到了这个工作。感谢@MaurizioIndenmark。
虽然我已经删除了ko.applybindings的多个调用,但我仍然多次调用视图模型。这导致了这个问题。
现在,我有了更清晰的视图模型,我对不同的操作有不同的函数调用,并修改了在这些函数(事件)中需要修改的所有数据。现在,一切都按预期工作。
这就是视图模型现在的样子 -
function ShipmentReportsViewModel(results) {
var self = this;
self.Heading = ko.observable();
self.BusinessUnits = ko.observableArray();
self.FrontEndUnits = ko.observableArray();
self.SalesSegments = ko.observableArray();
self.Home = function () {
var bu = FetchBusinessUnits();
self.Heading("Business Units");
self.BusinessUnits(bu);
self.FrontEndUnits(null);
self.SalesSegments(null);
};
self.fnFeu = function (businessUnit) {
var feu = FetchFrontEndUnits(businessUnit);
self.Heading(feu[0].BusinessUnit);
self.FrontEndUnits(feu);
self.BusinessUnits(null);
self.SalesSegments(null);
};
self.fnSalesSeg = function (frontEndUnit) {
var ss = FetchSalesSegments(frontEndUnit);
self.Heading(ss[0].BusinessUnit + ' - ' + ss[0].FrontEndUnit);
self.SalesSegments(ss);
self.BusinessUnits(null);
self.FrontEndUnits(null);
};
self.Home();
}
要查看整个工作解决方案,请参阅此jsFiddle
感谢所有有价值的建议。