2013-07-22 27 views
29

給定一個指令(container1)與transclude和隔離範圍,在該指令被鏈接然後我有這些範圍:爲什麼ng-transclude的範圍不是其指令範圍的子節點 - 如果指令具有隔離範圍?

Scope 004   <-- scope of the body 
    Scope 005  <-- scope of directive container1 
    Scope 006  <-- scope of the ng-transclude 

我預計:

Scope 004   <-- scope of the body 
    Scope 005  <-- scope of the directive 
     Scope 006 <-- scope of the ng-transclude 

如果同一指令有一個共享範圍而不是隔離範圍,我得到了預期的結果。

這使我一個問題,因爲,如果transcluded內容包含另一個指令(component1)與分離的範圍,我得到:

Scope 004    <-- scope of the body 
    Scope 005   <-- scope of the directive 
    Scope 006   <-- scope of the ng-transclude 
      Scope 007 <-- scope of directive component1 

我想用這樣的指令:

<container1> 
    <component1 data="objectExposedInContainer1"/> 
</container1> 

但這不起作用,component1$scope.data內部爲undefined,因爲objectExposedInContainer1不在正確的範圍內。

我有兩個問題:

  • 爲什麼ng-transclude的範圍不是其指令的範圍的孩子,如果該指令具有隔離範圍是什麼?這是一個錯誤?
  • 如果不是bug,容器指令如何通過設置像我嘗試的屬性來傳遞數據到它的內容。

下面是一個它不起作用的示例:http://plnkr.co/edit/NDmJiRzTF9e5gw8Buht2?p=preview。由於Plunker與Anguar一起構建,因此很難用Batarang進行調試。我建議在本地下載代碼。使用共享範圍註釋掉app.jsline 10以使其工作。

+0

1)不,你有你問什麼了 - 該指令的範圍是孤立的。 2)使用共享控制器。 –

+0

@Joe Gauterin,看看這個新樣本:http://plnkr.co/edit/Bv7B4OokkLi8bIctCIl3。這裏'container1'包含'component1',但不使用'ng-transclude'。這一次,即使兩者都有獨立的範圍,它們的範圍具有正確的父母/子女關係。 「ng-transclude」的存在改變了結果。 – Sylvain

回答

29

爲什麼ng-transclude的作用域不是其指令作用域的子級,如果該指令具有隔離作用域?

ng-transclude旨在允許指令使用任意內容,而隔離範圍旨在允許指令封裝其數據。

如果ng-transclude沒有保留那樣的作用域,那麼任何你要跨越的任意內容都需要知道你的指令的實現細節(即它需要知道你創建的隔離作用域上有什麼可用的內容)。

如果它不是一個bug,容器指令如何通過設置像我嘗試的屬性來傳遞數據到它的內容。

如果容器指令和包含的指令是耦合的 - 也就是說你寫了它們並且需要它們一起行動 - 那麼它們應該通過共享控制器進行通信。

如果容器指令應該將內容注入到子項的範圍內(例如,ng-repeat),那麼你不應該使用一個孤立的範圍。


角文檔是什麼行爲應該是很清楚的:

「在典型的設置窗口小部件創建一個分離的範圍,但 transclusion是不是一個孩子,而是隔離範圍的一個兄弟,這個小部件可以擁有私有狀態,並且 包含了綁定到父(預隔離)範圍的可能性。「

+1

感謝您的全面解答。 – Sylvain

+0

我創建了一個工作,但我不確定最佳實踐,我希望你們有空餘時間檢查一下嗎?這是一種自定義的transclude hack,可確保在鏈接階段創建新的兒童隔離範圍。這會創建父級 - >子級別,因此我們可以在控制器中使用$ emit和$ on。 https://gist.github.com/meanJim/1c3339bde5cbeac6417d – Jim

+1

我也採用了類似於@Jim的方法和我也是不知道這是否是最好的做法。你可以在這裏找到一個plunk:http://plnkr.co/edit/Ph5lMl0ol8ayXOFr7eal –

11

您可以手動transclude子元素

link: function(scope, element, attrs, ctrl, transclude) { 
    transclude(scope, function(clone, scope) { 
     element.find('.transclude-placeholder').append(clone); 
    }); 
} 
3

頂端回答是唯一正確的角度高達1.2。

由於角V1.3的行爲發生了變化,而正是因爲在這個問題的:「我希望」部分中描述,使得這個問題已經過時了角V1.3 +它現在的行爲。

來源:https://github.com/angular/angular.js/commit/fb0c77f0b66ed757a56af13f81b943419fdcbd7f

+0

嗨,我剛剛更新了示例到1.3.15,它仍然做同樣的事情。 http://plnkr.co/edit/PGsJRngCTCzstz85V80C?p=preview。我也嘗試了1.4,我得到了同樣的結果。註釋? – Sylvain

+0

事實上,今天我問了一個問題,我根據這個答案自己提供了一個答案! http://stackoverflow.com/questions/38267288/force-scope-to-named-slot-with-ng-transclude/38273990#38273990 –