iT邦幫忙

DAY 17
2

我在前端 ng 時系列 第 17

初談 directive - isolate scope

isolate scope - 獨立的 scope。

當設定 scope 為 isolate scope 的時候,我們可以確保只給 directive 需要知道的資料。
因此 directive 不會意外地覆蓋 parent scope 的值,讓我們不用擔心修改 isolate scope 會影響到外面的 scope。
isolate scope 非常適合做可重複利用的 directive。

個人覺得應該讓每一個 類型是 element directive 盡量做到都是 isolate scope。
因為可重複利用的特性才符合 element directive 的想法。
attribute directive 就看特性在決定要不要做成 isolate scope,可是假如會修改到 parent scope 的值,我建議都做成 isolate scope。

scope: {}

昨天的範例再修改一下,完成 myDirective 裡頭的值都是獨立的,
在 directive 修改不會影響到 parent scope value。
範例:http://plnkr.co/edit/TmnNfmOphqzYhAH7gWYU

app.directive('myDirective', function() {
    return {
      // 產生 isolate scope
      scope: {},
      template:
          '<div>' +
            '名稱:<input type="text" ng-model="myName"/>' +
            '抬頭:<input type="text" ng-model="myObj.title" />' +
          '</div>'
    };
  });

範例裡的 myDirective input 現在修改的值都是存在 myDirective 本身的 scope 裡。


在 isolate scope 宣告屬性的方法:

屬性宣告方式是在 DOM 元素裡加上 attribute,並且在 scope: {} 裡宣告對應的 scope 屬性。
命名規則跟 directive name 一樣,在宣告是要用駝峰寫法,在 HTML 中要改成破折號 (-) 寫法。

ex:

<div my-attr-value=“some value”></div>
scope: {
     myAttrValue: ‘=myAttrValue'
}

1. one-way data binding
scope: { value: ‘@‘, value: ‘@attr’ }

該屬性的類型傳進 directive 都會是 String。(因為 HTML 的 attribute 都是 string type)
one-way data binding 特性是當 parent scope 屬性改變,directive 的內容會改變。
可是,當 directive 屬性改變,parent scope 屬性不會跟者改變。

範例:http://plnkr.co/edit/Ac5PTDbO78rXraZMkfRJ

<body ng-app="myExample" ng-controller="myCtrl">
  <!-- 取得 scope 變數需要用 {{}} 包住才會執行 -->
  <div my-directive my-name=" hello {{myName}}" title="{{myObj.title}}"></div>
  <!-- 假如沒有用 {{}}包住,就直接是 pass string value 進去 -->
  <div my-directive my-name=" hello string name"></div>
  <hr>
  <!-- 修改上面 input value 並不會改變 parent scope。(one-way binding)-->
  <div>parent:</div>
  <div>myName: {{myName}}</div>
  <div>obj.title: {{myObj.title}}</div>


app.directive('myDirective', function() {
    return {
      scope: {
        // default attr name 就是跟屬性名稱一樣 'myName'
        myName: '@',
        myTitle: '@title'
      },
      template:
          '<div>' +
            '名稱:<input type="text" ng-model="myName"/>' +
            '抬頭:<input type="text" ng-model="myTitle" />' +
          '</div>'
    };
  });
  1. two-way data binding
    scope: { value: ‘=‘, value: ‘=attr’ }

在 parent scope 跟 directive scope 中產生 two-way binding。
修改了 directive scope 屬性,對應的 parent scope 屬性也會跟者換。(類似 ng-model )

範例:http://plnkr.co/edit/Zov9Pt1Ih5uV4HhQJKJi

<body ng-app="myExample" ng-controller="myCtrl">
  <!-- 取得 scope 變數不需要用 {{}} 包住 -->
  <div my-directive my-name="myName" title="myObj.title"></div>
  <!-- default 是會尋找 scope.myName,假如宣告的名稱沒有在 scope 出現會有 $parse:syntax error -->
  <!-- ex: <div my-directive my-name="hello string name"></div> -->
  <!-- 在使用 '=' 的情況下想要 pass sting 的用法就是在外面包 '' -->
  <!-- 在自己寫的 directive 假如一定會 pass string 請用第一點的@ 用法 -->
  <div my-directive my-name="'my string'"></div>
  <hr>
  <!-- 修改上面 input value 會改變 parent scope。(two-way binding)-->
  <div>parent:</div>
  <div>myName: {{myName}}</div>
  <div>obj.title: {{myObj.title}}</div>







app.directive('myDirective', function() {
    return {
      scope: {
        myName: '=',
        // 假如該屬性是非必須的,可在 = 後加 ?
        myTitle: '=?title'
      },
      template:
          '<div>' +
            '名稱:<input type="text" ng-model="myName"/>' +
            '抬頭:<input type="text" ng-model="myTitle" />' +
          '</div>'
    };
  });
  1. evaluating expressions
    scope: { value: ‘&‘, value: ‘&attr’ }

提供可以呼叫 parent scope function 的方法。

範例:http://plnkr.co/edit/p8cLCdH2OJlaiaehfFM6

<body ng-app="myExample" ng-controller="myCtrl">
  <!-- 傳送參數值的 function ex: update-name
    function 可以加上 argument 讓 directive 使用。ex: update-obj
    也可以直接在 html 定義 function (不建議在 HTML 中定義 function, ex: update-price)-->
  <div my-directive update-name="updateName()"
    update-price="myObj.price = myObj.price + 100"
    add-obj="addObjectKey(key)"></div>
  <hr>
  <div>myName: {{myName}}</div>
  <div>obj: {{myObj}}</div>
  <div>obj.price {{myObj.price}}</div>






angular.module('myExample')
  .directive('myDirective', function() {
    return {
      scope: {
        updateName: '&',
        updatePrice: '&updatePrice',
        addObjectKey: '&addObj'
      },
      // 注意: addObjectKey pass 的參數名稱必須要跟 HTML 定義的一模一樣
      // 並且需用 {} object 包住
      template:
          '<div>' +
            '<button ng-click="updateName()">更新名字</button>' +
            '<button ng-click="updatePrice()">更新價錢</button>' +
            '<div>增加 parent key <input ng-model="pValue">' +
            '<button ng-click="addObjectKey({key: pValue})">增加</button></div>' +
          '</div>'
    };
  });

最後放上示意圖

@ 是 one-way binding 所以是單向箭頭
= 是 two-way binding 所以是雙向箭頭
someIsolateProp 是 String (primary type),所以 directive scope 會去產生自己的 primary type value。

(圖片來源:AngularJS wiki - Understanding-Scopes)


有點關係的話題: transclude isolate scope
當設定 transclude = true 的時候,會自動產生一個 ng-transclude 的 isolate scope 在 directive scope 跟 parent scope 中間。
之後文章我會介紹 transclude 的用法,可是 transclude scope 照成影響我就先帶過了。
請直接看解說 >"<


上一篇
初談 directive - scope
下一篇
初談 directive - 完結
系列文
我在前端 ng 時30

尚未有邦友留言

立即登入留言