2012-11-07 66 views
2

我需要從knockout模板訪問整個可觀察數據上下文,而不僅僅是它的值。如何從knockoutjs模板中訪問數據上下文的observable

在我正在開發的應用程序中,我經常使用很多元數據來幫助一般呈現視圖。在過去,我所做的視圖模型性質複雜 - (中值屬性與值)都存儲元數據和副屬性的數據:

ViewModel.AwesomeProperty = { 
    value: ko.observable('Awesome Value'), 
    label: 'My Awesome Label', 
    template: 'awesomeTemplate', 
    otherMetaData: 'etc' 
} 

我改變了這個元數據成爲性能(我相信Ryan Niemeyer在其博客文章或會話中描述的)。我發現它更清潔,更優雅,並且通常更易維護,開銷更少(特別是在序列化時)。等效於上述的例子將如下所示:

ViewModel.AwesomeProperty = ko.observable('Awesome Value'); 
ViewModel.AwesomeProperty.label = 'My Awesome Label'; 
ViewModel.AwesomeProperty.template = 'awesomeTemplate'; 
ViewModel.AwesomeProperty.otherMetaData = 'etc'; 

這樣做的副作用是通過ViewModel.AwesomeProperty到模板設置爲可觀察的值的數據上下文(在這種情況下「真棒價值「),使將元數據從$數據無法訪問:

<script id="example" type="text/html"> 
    <!-- This won't work anymore --> 
    <span data-bind="text: $data.label></span> 
</script> 
<div data-bind="template: {name: 'example', data: AwesomeProperty}"></div> 

的解決方法我現在已經是包的數據值在一個匿名對象,像這樣:

<script id="example" type="text/html"> 
    <!-- Now it works again --> 
    <span data-bind="text: data.label></span> 
</script> 
<div data-bind="template: {name: 'example', data: {data:AwesomeProperty}}"></div> 

但這是不雅和不理想的。在有很多自動生成的情況下,這不僅不方便,而且實際上是一個主要障礙。我考慮做一個自定義綁定來包裝模板綁定,但我希望有一個更好的解決方案。

下面是我一直在爲級聯下拉菜單工作的真實世界示例。 This JSFiddle作品,但​​沒有。

在此先感謝。

回答

1

事情是,淘汰賽將始終使用該值後解包。如果它碰巧是可觀察的,你將失去這些子屬性。你必須將你的observable重新封裝到另一個對象中,所以你不會像已經找到的那樣丟失它。

你可以包裝它的一個好方法是爲subscribables(或任何更派生的類型)創建一個函數,它將執行此重新包裝。您可以將所有單獨的元數據粘貼到這個重新包裝的對象上,也可以將它們組裝到它們自己單獨的對象中。你的代碼可以再次優雅。

var buildSelection = function (choices, Parent) { 
    return _(ko.observable()).extend({ 
     // add the metadata to a 'meta' object 
     meta: { 
      choices: choices, 
      availableChoices: ko.computed(function() { 
       if (!Parent) return choices; 
       if (!Parent()) return []; 
       return _(choices).where({ ParentID: Parent().ID }); 
      }) 
     } 
    }); 
} 

ko.subscribable.fn.templateData = function (metaName) { 
    return { 
     // access the value through 'value' 
     value: this, 
     // access the metadata through 'meta' 
     meta: this[metaName || 'meta'] // meta property may be overridden 
    }; 
} 

然後在你的綁定,調用這個函數來創建重新包裝對象。只要記住在你的模板中調整你的綁定。

<script id="Selection" type="text/html"> 
    <select data-bind=" 
      options: meta.availableChoices, 
      optionsText: 'Value', 
      value: value, 
      optionsCaption: 'Select One', 
      enable: meta.availableChoices().length 
    "></select> 
</script> 

<!-- ko template: { 'name': 'Selection', 'data': Level1.templateData() } --><!-- /ko --> 
<!-- ko template: { 'name': 'Selection', 'data': Level2.templateData() } --><!-- /ko --> 
<!-- ko template: { 'name': 'Selection', 'data': Level3.templateData() } --><!-- /ko --> 

Updated fiddle

相關問題