【问题标题】:Knockout: Complex binding with observable arrays and checkboxes淘汰赛:与可观察数组和复选框的复杂绑定
【发布时间】:2012-12-18 03:39:18
【问题描述】:

我有一系列可能由公司提供的服务(即销售、服务、咨询)。这些服务中的每一项都可以由公司在零个或多个美国州执行,并且每个州都有一个可选的认证编号。因此,Service 有一个可观察的 Locations 数组,而 Location 是 State 和 Cert Number 的组合。

function Service(name) {
    var self = this;

    self.Name = ko.observable(name);
    self.Locations = ko.observableArray();
}

function Location(state) {
    var self = this;

    self.State = ko.observable(state);
    self.CertNum = ko.observable();
}

在用户界面中,我想显示所有美国州的单个列表。用户将勾选公司运营所在的每个州旁边的复选框,从而制作州的“主列表”。反过来,这个主列表驱动出现在每个可能服务下的选择。

例如,用户在主列表中勾选“阿拉巴马州”和“亚利桑那州”。 UI 然后将每个服务的单独位置呈现为复选框和文本框的组合。这是主视图模型:

function viewModel() {
    var self = this;

    self.AllStates = [
        { name: "Alabama", abbrev: "AL" },
        { name: "Alaska", abbrev: "AK" },
        { name: "Arizona", abbrev: "AZ" },
        { name: "Arkansas", abbrev: "AR" }
    ];

    self.BusinessStates = ko.observableArray();

    self.AllSelectedStates = ko.computed( function() {
        return ko.utils.arrayFilter( self.AllStates, function(item) {
            return self.BusinessStates.indexOf(item.abbrev) >= 0;
        });
    });

    self.Services = ko.observableArray([
        new Service("Sales"),
        new Service("Service"),
        new Service("Consulting")
    ]);
}

一个简单的视图如下所示:

<h2>Master List</h2>
<ul data-bind="foreach: AllStates">
    <li>
        <label><input type="checkbox" data-bind="value: abbrev, checked: $root.BusinessStates"/> <span data-bind="text: name"></span></label></li>
</ul>

<h2>Services</h2>
<div class="service" data-bind="foreach: Services">
    <h3 data-bind="text: Name"></h3>
    <ul data-bind="foreach: $root.AllSelectedStates">
        <li>
           <label>
             <input type="checkbox" data-bind="value: abbrev, checked: $parent.Locations" /> 
             <span data-bind="text: name"></span>
           </label> 
           <input type="text" placeholder="Cert. Number" data-bind="value: ??" />
        </li>
    </ul>
</div>

该视图至少让我在 Service 的 Locations 数组中输入了一个状态,但我不知道如何绑定 CertNum 属性。

假设用户在主列表中选择了阿拉巴马州和亚利桑那州。现在,对于“销售”服务,用户勾选“亚利桑那”并输入“98765”的认证号码。在“咨询”服务下,用户勾选“阿拉巴马州”并且不输入证书编号。理想情况下,我希望生成的 JSON sn-p 看起来像:

"Services": [
    {
        "Name": "Sales",
        "Locations": [
            {
                "State": { "name": "Arizona", "abbrev": "AZ" },
                "CertNum": "98765"
            }
        ]
    },
    {
        "Name": "Service",
        "Locations": []
    },
    {
        "Name": "Consulting",
        "Locations": [
            {
                "State": { "name": "Alabama", "abbrev": "AL" },
                "CertNum": null
            }
        ]
    }
]

我可以渲染和绑定美国的“主列表”。我可以遍历服务并呈现为每个可用服务位置提供控件的 UI(即状态复选框,证书编号的文本框)。我无法绑定服务位置控件以控制相应位置数组中位置的成员资格,并同时影响证书编号的值。

我所做的最接近的尝试非常复杂和 hacky,我使用 knockout-postBox plugin 将 viewModel.AllSelectedStates 属性链接到每个服务模型上的类似属性,然后将新位置推送到每个服务中。位置数组。它几乎可以工作,只是它会在主列表中选中或取消选中状态时清除对服务的更改。此外,我必须将每个可用位置推送到每个服务的 Locations 数组中,并依靠位置上的 IsSelected 布尔标志来确定它是否已被选中(我宁愿将位置 just 放在被选中的数组)。

您可以在此 JSFiddle 中看到尝试:http://jsfiddle.net/cbono/PU6Sq/23/

它的好处是它展示了 UI 的行为方式。但我认为如果没有 postBox 插件,这是可能的,我只是没有以正确的方式来解决问题。我已经花了几天时间解决这个问题,但无法提出一个 100% 有效的解决方案。

【问题讨论】:

    标签: knockout.js knockout-2.0


    【解决方案1】:

    使用visible-binding 比管理集合事件更容易。

    <li data-bind="visible: State().IsSelected">
    

    http://jsfiddle.net/MizardX/XTkpb/


    如果你真的需要处理它们,你可以将StateAndCert对象缓存在Services对象中:

    var self = this,
        cache = {};
    
    self.Locations = ko.computed(function () {
        return ko.utils.arrayMap(states(), function (item) {
            var key = item.Abbrev();
            if (cache[key] === undefined) {
                cache[key] = new StateAndCert(item);
            }
            return cache[key];
        });
    });
    

    http://jsfiddle.net/MizardX/HMAtE/


    要在 JSON 渲染中隐藏某些属性,您可以将它们填充到 function(){} 属性中:

    self.Meta = function(){};
    self.Meta.IsSelected = ko.observable(false);
    

    【讨论】:

    • 谢谢,马库斯。我没有完全使用您的解决方案,但是您帮助我走上了正确的道路。将一组可观察的项目从一个模型发送到另一个模型是我没有想到的。但是,我没有发送整个 States 数组,而是创建了一个依赖的 observable,它被过滤到仅选定的状态并使用它。像魅力一样工作!
    猜你喜欢
    • 1970-01-01
    • 2012-09-08
    • 2014-06-13
    • 2014-09-28
    • 2014-08-22
    • 2015-10-05
    • 1970-01-01
    • 2014-06-23
    相关资源
    最近更新 更多