我有一组可观察的服务,可能由公司提供(即销售,服务,咨询)。这些服务中的每一个可以由公司在零个或多个美国州执行,并且对于每个州,存在可选的认证号。因此,该服务具有可观察的一系列位置,而位置是州和证书号的组合。
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();
}
在用户界面中,我想显示所有美国州的单个列表。用户将勾选公司运营所在的每个州旁边的复选框,从而形成州的“主列表”。反过来,该主列表驱动每个可能服务下出现的选择。
例如,用户在主列表中勾选“Alabama”和“Arizona”。然后,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属性。
假设用户已在主列表中选择了Alabama和Arizona。现在,对于“销售”服务,用户勾选“亚利桑那州”并输入认证号“98765”。在“咨询”服务下,用户勾选“Alabama”并且不输入证书编号。理想情况下,我希望生成的JSON代码段看起来像:
"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属性链接到每个Service模型上的类似属性,然后将新的Locations推送到每个Service.Locations数组。 几乎可以工作,只要在主列表中选中或取消选中状态时,它会清除对服务的更改。此外,我必须将每个可用位置推送到每个服务的Locations数组中,并依赖该位置上的IsSelected布尔标志来确定它是否已被选中(我宁愿将仅位置放入被选中的数组。)
您可以在此JSFiddle中看到此尝试:http://jsfiddle.net/cbono/PU6Sq/23/
关于它的好处是它演示了UI应该如何表现。但我认为没有postBox插件就可以实现这一点,我只是没有找到解决问题的正确方法。我花了几天时间来完成这项工作,无法提出100%的解决方案。
答案 0 :(得分:0)
使用visible
- 绑定比管理集合事件更容易。
<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);