Javascript 如何使用淘汰赛迭代对象(不是数组)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14838135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use knockout to iterate over an object (not array)
提问by John Livermore
I want to use something similar to the Knockout foreach construct to iterate over the properties of an object. Here is what I am trying to create...
我想使用类似于 Knockout foreach 构造的东西来迭代对象的属性。这是我正在尝试创建的内容...
DESIRED RESULT
想要的结果
<table>
<tr>
<td>Name 1</td>
<td>8/5/2012</td>
</tr>
<tr>
<td>Name 2</td>
<td>2/8/2013</td>
</tr>
</table>
However, my model looks like this...
但是,我的模型看起来像这样......
JS
JS
function DataModel(){
this.data = ko.observableArray([{
entityId: 1,
props: {
name: 'Name 1',
lastLogin: '8/5/2012'
}
},
{
entityId: 2,
props: {
name: 'Name 2',
lastLogin: '2/8/2013'
}
}]);
}
var dataModel = new DataModel();
ko.applyBindings(dataModel);
Each row has an entityId and props which is an object itself. This template doesn't work, but how would I change it to generate the desired table above?
每行都有一个 entityId 和 props,它本身就是一个对象。此模板不起作用,但我如何更改它以生成上面所需的表格?
EDIT: The propsin this example are nameand lastLogin, but I need a solution that is agnostic to what is contained inside props.
编辑:props在这个例子中是nameand lastLogin,但我需要一个与里面包含的内容无关的解决方案props。
I have this FIDDLEgoing as well.
我也有这个FIDDLE。
HTML
HTML
<div data-bind="template: { name: 'template', data: $data }"></div>
<script type="text/html" id="template">
<table>
<tr data-bind="foreach: data()">
<td data-bind="text: entityId"></td>
</tr>
</table>
</script>
回答by o.v.
In a modern browser (or with an appropriate polyfill) you can iterate over Object.keys(obj)(the method returns only own enumerable properties, meaning that there is no need for an additional hasOwnPropertycheck):
在现代浏览器(或使用适当的 polyfill)中,您可以迭代Object.keys(obj)(该方法只返回自己的可枚举属性,这意味着不需要额外的hasOwnProperty检查):
<table>
<tbody data-bind="foreach: {data: data, as: '_data'}">
<tr data-bind="foreach: {data: Object.keys(props), as: '_propkey'}">
<th data-bind="text: _propkey"></th>
<td data-bind="text: _data.props[_propkey]"></td>
</tr>
</tbody>
</table>
摆弄。
NB:I was simply curious to see if this would work, the template body above is more polluted than what I'd like to use in production (or come back to a few months later and be like "wtf").
注意:我只是想知道这是否可行,上面的模板主体比我想在生产中使用的污染更严重(或者几个月后回到像“wtf”一样)。
Custom binding would be a better option, my personal preference though would be to use a computed observable or a writeable computed observable(the latter would be handy when working with jsonresponses a-la restful api).
自定义绑定将是一个更好的选择,但我个人的偏好是使用计算的 observable 或可写的计算 observable(后者在处理json响应 a-la restful api时会很方便)。
回答by Jeff Mercado
You could always create a binding handler to handle the transformation.
您始终可以创建一个绑定处理程序来处理转换。
ko.bindingHandlers.foreachprop = {
transformObject: function (obj) {
var properties = [];
ko.utils.objectForEach(obj, function (key, value) {
properties.push({ key: key, value: value });
});
return properties;
},
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var properties = ko.pureComputed(function () {
var obj = ko.utils.unwrapObservable(valueAccessor());
return ko.bindingHandlers.foreachprop.transformObject(obj);
});
ko.applyBindingsToNode(element, { foreach: properties }, bindingContext);
return { controlsDescendantBindings: true };
}
};
Then apply it:
然后应用它:
<div data-bind="template: { name: 'template', data: $data }"></div>
<script type="text/html" id="template">
<table>
<tbody data-bind="foreach: data">
<tr data-bind="foreachprop: props">
<td data-bind="text: value"></td>
</tr>
</tbody>
</table>
</script>
回答by Jitters
This is a modification of Jeff's answer, with the binding context preserved
这是对 Jeff 回答的修改,保留了绑定上下文
ko.bindingHandlers.eachProp = {
transformObject: function (obj) {
var properties = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
properties.push({ key: key, value: obj[key] });
}
}
return ko.observableArray(properties);
},
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.utils.unwrapObservable(valueAccessor()),
properties = ko.bindingHandlers.eachProp.transformObject(value);
ko.bindingHandlers['foreach'].init(element, properties, allBindingsAccessor, viewModel, bindingContext)
return { controlsDescendantBindings: true };
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.utils.unwrapObservable(valueAccessor()),
properties = ko.bindingHandlers.eachProp.transformObject(value);
ko.bindingHandlers['foreach'].update(element, properties, allBindingsAccessor, viewModel, bindingContext)
return { controlsDescendantBindings: true };
}
};
Now apply with parent and root:
现在与父和根一起申请:
<table>
<tbody data-bind="foreach: data">
<tr data-bind="eachProp: props">
<td data-bind="text: value, click: $root.doSomething"></td>
</tr>
</tbody>
</table>
回答by Andrew
Simplified answer to work with any basic object, worked for me:
使用任何基本对象的简化答案,对我有用:
<!-- ko foreach: {data: Object.keys(myObj)} -->
<span data-bind="text: $data"></span>
<span data-bind="text: $parent.myObj[$data]"></span>
<!-- /ko -->
回答by Sufiyan Ansari
I am a bit late, But I think this should work, a simple solution without using any template.
我有点晚了,但我认为这应该可行,这是一个不使用任何模板的简单解决方案。
var json = [
{
"PortfolioCompanyId":240,
"dt":"2018-12-31 00:00:00.0",
"ValuationDate":"2017-09-30 00:00:00.0",
"capitalexpenditure":-5555660.0,
"workingcapitalchange":-812350.0
},
{
"PortfolioCompanyId":240,
"dt":"2019-12-31 00:00:00.0",
"ValuationDate":"2017-09-30 00:00:00.0",
"capitalexpenditure":-5613520.0,
"workingcapitalchange":-893530.0
},
{
"PortfolioCompanyId":240,
"dt":"2020-12-31 00:00:00.0",
"ValuationDate":"2017-09-30 00:00:00.0",
"capitalexpenditure":-5674130.0,
"workingcapitalchange":-982850.0
},
{
"PortfolioCompanyId":240,
"dt":"2021-12-31 00:00:00.0",
"ValuationDate":"2017-09-30 00:00:00.0",
"capitalexpenditure":-6241543.0,
"workingcapitalchange":-1081135.0
},
{
"PortfolioCompanyId":240,
"dt":"2022-12-31 00:00:00.0",
"ValuationDate":"2017-09-30 00:00:00.0",
"capitalexpenditure":-6865697.3,
"workingcapitalchange":-1189248.5
}
];
var DataModel = function () {
this.jsonArray = ko.observable(json);
};
ko.applyBindings(new DataModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table" data-bind="foreach:jsonArray">
<tr data-bind="foreach:Object.keys($data)"> <!-- JSON Object -->
<td data-bind="text : $parent[$data]"></td>
</tr>
</table>
回答by Cody
<table>
<tr data-bind="foreach: {data: data, as: 'item'}">
<td data-bind="foreach: { data: Object.keys(item), as: 'key' }">
<b data-bind="text: item[key]"></b>
</td>
</tr>
</table>
function DataModel(){
this.data = ko.observableArray([{
entityId: 1,
props: {
name: 'Name 1',
lastLogin: '8/5/2012'
}
},
{
entityId: 2,
props: {
name: 'Name 2',
lastLogin: '2/8/2013'
}
}]);
}
var dataModel = new DataModel();
ko.applyBindings(dataModel);
Hope that's helpful (pardon the brevity)
希望这会有所帮助(请原谅篇幅太短)
appendix:
附录:
Here's a working example which has been testing...
这是一个正在测试的工作示例......
<table class="table table-hover">
<thead>
<tr>
<!-- ko foreach: gridOptions.columnDefs -->
<th data-bind="text: displayName"></th>
<!-- /ko -->
</tr>
</thead>
<tbody>
<!-- ko foreach: {data: gridOptions.data, as: 'item'} -->
<tr>
<!-- ko foreach: {data: Object.keys(item), as: 'key'} -->
<td>
<span data-bind="text: item[key]"></span>
</td>
<!-- /ko -->
</tr>
<!-- /ko -->
</tbody>
</table>
回答by Jakub Macek
Supposedly, there is a deeper problem (see this thread at Google groups) that is that foreach treats the object as a dictionary of parameters, not as the collection to iterate.
据说,还有一个更深层次的问题(请参阅 Google 群组中的此线程),即 foreach 将对象视为参数字典,而不是要迭代的集合。
My best solution so far is to combined foreachin Object.keys(myobject)and 'with' binding context.
我最好的解决办法,到目前为止是要结合foreach在Object.keys(myobject)和“用”结合上下文。
回答by paul
(not strictly iterating over the properties, but doescreate the table above)
(不是严格迭代属性,但确实创建了上面的表格)
<div data-bind="template: { name: 'template', data: $data }"></div>
<script type="text/html" id="template">
<table data-bind="foreach: data()">
<tr>
<td data-bind="text: props.name"></td>
<td data-bind="text: props.lastLogin"></td>
</tr>
</table>
</script>
updated: http://jsfiddle.net/cwnEE/7/

