2013-02-12 73 views
39

我想使用類似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和道具,它們本身就是一個對象。這個模板不起作用,但我如何改變它來生成上面所需的表格?

編輯:在這個例子中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> 
+0

是道具的數量總是2或者他們可以彼此之間有什麼不同? – 2013-02-14 11:20:09

回答

45

你總是可以創建一個綁定處理程序來處理轉換。

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

作爲一個對象返回值,爲什麼它不能只是一個像鍵一樣的字符串? – 2013-05-21 15:25:15

+0

只是想知道這個foreachprop綁定是否可以使用'$ parent.'綁定上下文? – Thewads 2014-01-09 08:56:20

+0

@Thewads:當然。您可以將它用於具有屬性的任何普通對象。雖然我不確定我明白你指的是什麼。 – 2014-01-23 02:10:55

0

(在性能沒有嚴格的迭代,但創建上表)

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

+2

確實如此,但我需要它迭代屬性,因爲'道具'中的名稱對於不同的表格會有所不同。我編輯了這個問題來澄清這一點。 – 2013-02-12 17:31:59

53

在現代的瀏覽器(或用適當的填充工具),你可以在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> 

Fiddled

注:我只是好奇,想看看這是否會工作,模板身體上面比想什麼,我在生產中使用(或回來幾個月後,成爲像「跆拳道污染更嚴重「)。

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

+0

這個答案是撞。剛纔碰到了這個,我想我會檢查一下,因此不得不說。用於特定用途的自定義綁定不像生產大型網站那樣有效,因爲這是一種簡單的內聯解決方案。 – MattSizzle 2014-11-23 04:57:35

+0

我希望我可以多次調用這個函數。我喜歡這個,因爲我不必創建綁定處理程序。 – valdetero 2015-01-02 19:41:49

+0

這是最好的解決方案!我不明白爲什麼它不是第一個。 – jbartolome 2015-01-29 21:49:18

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

這是一個修改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> 
+2

這個答案比接受的IMO更好,因爲它包含更新函數..這意味着它不僅僅是一次迭代就會表現得像一個可觀察的事物。 – 2014-09-04 17:31:48

+0

@SteveCadwallader:它不會更好,有一個明確的'update'函數,它直接調用'foreach'處理程序的更新函數。換句話說,它是手動傳播更新調用。另一個答案將foreach處理程序應用於元素,以使foreach所做的一切都會發生(包括更新)。顯式更新函數是不需要的。 – 2017-04-21 00:59:21

2

據說,還有一個更深層次的問題(see this thread at Google groups)即是的foreach把對象作爲參數的字典,而不是作爲集合進行迭代。

我到目前爲止的最佳解決方案是將foreach合併到Object.keys(myobject)和'with'綁定上下文中。

0

簡化的答案與任何基本對象的工作,爲我工作:

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