當使用 AngularJS 客製化的 HTML 標籤 (Directive) 時,
要特別注意 Scope,下面敘述五種不同設定下的 Scope 差別。
預備知識
scope 和 transclude 的預設值皆為 false。1. Directives without attributes 'scope' and 'transclude'
這種情況下,directive 的 scope 就是 parent scope,沒有新建 scope,正常綁定(bind)沒有問題。
但很危險的是,若 directive 要可以重複使用,
因為都是使用 parent scope 的變數,很容易會變更到同一個變數,
而使結果不如預期。
2. Directives with attribute 'scope: true'
Ex: ng-if, ng-include, ng-switch, ng-controller, ng-template, ...etc這種情況下,directive 會新建一個 child scope 繼承 parent scope。
當改變 primitive 或者物件的值時,會在 child scope 建立一個新的同名稱變數,
而非使用原本 parent scope 的變數,例如:
<accordion> <accordion-group> <accordion-heading> ... </accordion-heading> <input type="text" ng-model="name" /> </accordion-group> </accordion>name 在 parent scope 裡面是字串型態的變數,
在 input 中改變值時,並不會改變到 parent scope 的 name 變數,
解決方式
<accordion> <accordion-group> <accordion-heading> ... </accordion-heading> <input type="text" ng-model="$parent.$parent.name" /> </accordion-group> </accordion>這是最容易混淆的地方。
當改變物件內屬性的值時,則會如預期般,改變 parent scope 的變數的值。
3. Directives with attribute 'scope: {...}'
這種情況下,directive 的 child scope 是一個 isolate scope,無法存取到 parent scope 的東西,
要用 '=' 、 '@' 、 '&' 和標籤的屬性設定才能做雙向、單向或陳述和 parent scope 的綁定(bind)。
雖然新建的 child scope 不繼承 parent scope,
但還是可以透過 $parent 取得 parent scope 的東西,
所以還是算 child scope。
4. Directives with attribute 'transclude: true'
這種情況下,directive 會新建一個繼承 parent scope 的 transcluded child scope,情況跟第二種相同,
如果 directive 裡面有 isolate scope,兩者是 sibling 的關係,
彼此不相關,只是有同一個 parent scope。
5. ng-repeat 等迴圈式、重複式 directives
這種情況下,會根據 element 數量建立出多少個 child scopes,而 elements 在每一個自己的 child scope 內複製一份新的 element,
所以在使用 ng-repeat 時,如果在裡面去更動 element 的值,
並不會更動到 parent scope 陣列裡面的 element 的值。
解決方式
把 elements 從 primitives (studentName) 或物件 (student) 改為物件的屬性 (student.name) 。
參考
原始資料 (附圖示!) 可以參考 Understanding Scopes 。
不過最原始的資料是從 這邊 來的。
P.S.
這概念跟設定 nameA = nameB 類似。
讀一讀發現是你誒,嗨!
回覆刪除小朱!好久不見~~
刪除還請多多指教<(_ _)>