使用knockoutJS,如何将列表项绑定到同一视图?

时间:2013-06-10 06:30:21

标签: javascript knockout.js

我是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示例中没有完成主页和后退按钮功能。)

如果需要更多详细信息,请与我们联系。我确实在堆栈溢出中查看了很多其他链接,但没有解决这个特定问题。

非常感谢任何帮助。提前谢谢。

2 个答案:

答案 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

感谢所有有价值的建议。