簡體   English   中英

如何使用knockout迭代一個對象(不是數組)

[英]How to use knockout to iterate over an object (not array)

我想使用類似於Knockout foreach構造的東西來迭代對象的屬性。 這是我想要創造的......

期望的結果

<table>
    <tr>
        <td>Name 1</td>
        <td>8/5/2012</td>
    </tr>
    <tr>
        <td>Name 2</td>
        <td>2/8/2013</td>
    </tr>
</table>

但是,我的模型看起來像這樣......

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);

每行都有一個entityId和props,它們本身就是一個對象。 此模板不起作用,但我如何更改它以生成上面所需的表?

編輯:這個例子中的propsnamelastLogin ,但我需要一個與props包含的內容無關的解決方案。

我也有這個FIDDLE

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>

在現代瀏覽器中(或使用適當的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>

擺弄

注意:我只是很好奇,看看這是否有效,上面的模板體比我想要在生產中使用的更污染(或者回到幾個月之后,就像“wtf”)。

自定義綁定是一個更好的選擇,我個人的偏好雖然是使用計算的observable或可寫的計算observable (后者在使用json響應a-la restful api時會很方便)。

您始終可以創建一個綁定處理程序來處理轉換。

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 };
  }
};

然后申請:

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

這是對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 };
    }
};

現在申請父和根:

<table>
    <tbody data-bind="foreach: data">
        <tr data-bind="eachProp: props">
            <td data-bind="text: value, click: $root.doSomething"></td>
        </tr>
    </tbody>
</table> 

使用任何基本對象的簡化答案,對我有用:

<!-- ko foreach: {data: Object.keys(myObj)} -->
    <span data-bind="text: $data"></span> 
    <span data-bind="text: $parent.myObj[$data]"></span>
<!-- /ko -->
<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);

希望有幫助(原諒簡潔)

附錄:

這是一個正在測試的工作示例......

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

據推測,存在一個更深層次的問題( 參見Google小組的這個主題 ),即foreach將對象視為參數字典,而不是迭代的集合。

到目前為止,我最好的解決方案是在Object.keys(myobject)和'with'綁定上下文中組合foreach

(不嚴格迭代屬性,但確實創建上面的表)

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

更新: http//jsfiddle.net/cwnEE/7/

我有點遲了,但我認為這應該有用,一個簡單的解決方案,不使用任何模板。

 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> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM