2013-01-23 48 views
58

工作,我在這勢必模型name控制器已經一個文本框。還有的控制器內的指令和有指令內的另一個文本框被綁定到相同型號name雙向綁定不與指令範圍transcluded

<div class="border" ng-controller="editCtrl"> 
    Controller: editCtrl <br/> 
    <input type="text" ng-model="name" /> 
    <br/> 
    <tabs> 
     Directive: tabs <br/> 
     <input type="text" ng-model="name"/> 
    </tabs> 
</div> 

mod.directive('tabs', function() { 
    return { 
    restrict: 'E', 
    transclude: true, 
    template: 
     '<div class="border" ng-transclude></div>', 
    }; 
}); 

當你在外部文本框中輸入的東西會反映在內部文本但如果您在內部文本框中輸入某些內容,它將停止工作,即兩個文本框不再反映相同的值。

見例如在:http://jsfiddle.net/uzairfarooq/MNBLd/

我也使用兩種方式結合ATTR(scope: {name: '='})嘗試,但它提供了語法error.And使用scope: {name: '@'}具有同樣的效果。

任何幫助將不勝感激。

除了接受的答案,this article真的幫助我瞭解兒童scpoes原型繼承。我強烈建議任何有問題的人都可以仔細閱讀。

+0

無關,但我不會使用無效的HTML元素(「標籤」) –

+0

@ajkochanowicz這是沒有錯的,除非你想要支持那個古老而討厭的IE。儘管如此,還是有解決方法。 – Frizi

回答

128

transclude: true導致指令創建一個新的(transcluded)子作用域的指令。這個新的範圍原型從父範圍繼承。在你的情況下,父範圍是與editCtrl控制器關聯的範圍。

在孩子使用範圍雙向數據綁定(即,NG-模型)綁定到持有原始值父作用域屬性(例如,name)始終產生問題 - 嗯,我應該說,它不沒有按預期工作。當子項中的scope屬性發生更改(例如,您鍵入第二個文本框)時,子項創建一個新的範圍屬性,用於隱藏/隱藏相同名稱的父範圍屬性。如果父屬性包含原始值,則在創建子屬性時,該值(基本上)被複制到子屬性。子範圍的未來更改(例如第二個文本框)僅影響子屬性。

在鍵入第二個文本框之前(即在子級中更改屬性之前),子/跨行範圍通過原型繼承(下圖中的虛線)查找父範圍內的name屬性。這就是兩個文本框最初保持同步的原因。下面,如果鍵入「標記」到第一個文本框,這是示波器的樣子:

transcluded scope follows inheritance chain

我創建了一個fiddle在那裏你可以檢查兩個範圍。在輸入第二個文本框之前,單擊第二個文本框旁邊的「顯示範圍」鏈接。這將允許您查看被跨越的子範圍。您會注意到,此時它沒有name屬性。清除控制檯,鍵入第二個文本框,然後再次單擊該鏈接。您會注意到子範圍現在有一個name屬性,並且初始值是父屬性具有的值(「標記」)。如果你輸入「喜歡角」進入第二個文本框,這是該領域的樣子:

transcluded primitive hides parent property

解決辦法有兩個:

  1. 做什麼@ pgreen2建議(這是「最佳實踐」解決方案) - 使用對象而不是原語。當使用對象時,子/ transcluded作用域不會獲得新屬性。這裏只有原型繼承。在下面的圖片中,假設editCtrl的$範圍已定義這個對象:(這是一個脆弱的解決方案,而不是推薦,因爲它的前提關於HTML結構)在兒童範圍
    object in parent
  2. 使用$父:
    $scope.myObject = { name: "Mark", anotherProp: ... } :在< input>內使用ng-model="$parent.name",這是在< tabs>元素內。上面的第一張照片顯示了這是如何工作的

使用scope: {name: '='}時會出現語法錯誤,因爲使用雙向數據綁定時(即使用'='時),不允許使用插值 - 即{{}}不能使用。而不是<tabs name="{{name}}">使用<tabs name="name">

使用'@'的作用與transclude相同,因爲ng-transclude使用transcluded作用域,而不是使用scope: { ... }創建的隔離作用域。

對於(大量)有關作用域的詳細信息(包括圖片)看到
What are the nuances of scope prototypal/prototypical inheritance in AngularJS?

+0

非常感謝。這是更清楚的答案。 –

+4

@Uzair,我添加了一些圖片。(這將有希望幫助未來的讀者也來到這裏) –

+0

使用ng-transclude vs指定任何子div的優點是什麼? – Atav32

0

語法錯誤意味着你miswrote東西。它與特定的框架/庫無關。您可能忘了添加「,」或關閉palenthesis。檢查它再次

+2

是的,我知道什麼語法錯誤的意思,但我沒有看到任何語法錯誤。檢查它在這裏:http://jsfiddle.net/uzairfarooq/6pJrm/3/ –

10

我認爲,這個問題與範圍有關。最初,內部文本框沒有設置name,所以它從外部範圍繼承。這就是爲什麼在外框中輸入反映在內框中的原因。但是,一旦在內框中輸入,內部示波器現在包含name,這意味着它不再綁定到外部name,所以外部文本框不會同步。

適當的方式來解決只存儲模型的範圍,而不是你的價值觀。我將它固定在http://jsfiddle.net/pdgreen/5RVza/訣竅是創建一個模型對象(data)並在其上引用值。

不正確的代碼修改該指令的範圍,正確的代碼修改在指令範圍內的模型。這種細微的差異使得範圍繼承能夠正常工作。

我相信的樣子MISKO Hevery的話來說就是,範圍應只寫控制器,並只讀的指令。

更新:參考:https://www.youtube.com/watch?v=ZhfUv0spHCY#t=29m19s

+0

我最近看到與MiškoHevery談論這個非常相同的問題(這是我如何認識到它)的視頻。如果我能找到它,我會更新答案。 – pgreen2

+0

謝謝!這似乎解決了我的問題:) –

+3

哇..文檔應該反映這一點。非常棘手的問題。 –

相關問題