iT邦幫忙

DAY 18
0

我在前端 ng 時系列 第 18

初談 directive - 完結

再來繼續介紹 directive 屬性吧,補上 初談 directive 順序圖。

(為了教學流暢,介紹順序有點變更。數字不會變!)

8. transclude (default false)

使用 transclude 屬性可以讓 directive 的 template 包覆宣告該 directive element 裡的內容。
(假如沒有宣告 transclude,directive element 裡的內容被 directive template 完全覆蓋掉)

有兩種寫法:

  • transclude: true,directive template 會包覆 element 內容。
    範例:http://plnkr.co/edit/zbI4jLuqalJJNQTPwHjA

    app.directive('myDirective', function() {
    return {
    restrict: 'EA',
    scope: {},
    transclude: true,
    // 一定要定義 ng-transclude attr,來指定安插內容的點
    template: ''
    };
    });

結果:element 會包圍 directive template,並且把內容塞在 ng-transclude

  • transclude: ‘element’,整個 element 會被包進去
    http://plnkr.co/edit/2woXMWrScVQ1oPb7OT8g

    app.directive('myDirective', function() {
    return {
    restrict: 'EA',
    scope: {},
    transclude: 'element',
    // 搭配 replace: true 讓此 directive 有新的 rootnode
    replace: true,
    // 一定要定義 ng-transclude attr,來指定安插內容的點
    template: '',
    link: function (scope, element, attrs, ctrl, transclude) {

           // 也可以從 link 或 controller 取得 transclude 操作
           transclude(scope, function (clone) {
             element.after('<div> append from link function </div>');
           })
        }
     };
    

    });

結果:element 會整個被包在 ng-transclude 裡面

7.1 controller

directive controller 裡頭可放置跟其他 directive 分享的 method 或參數,方便讓 directive 彼此溝通。
(互相溝通的宣告請看 9.require 屬性)

在 directive 的 controller 裡頭可以 DI,$scope, $element, $attrs, $transclude (用法跟 link function 一樣)

7.2 controllerAs

需要跟 controller 同時出現,定義 controller 的別名。

app.directive('myDirective', function() {
    return {
      scope: {},
      controller: function () {
          this.value = “hello”;
      },
      controllerAs: 'MyCtrl'
    }

 <div>
   <!--取得 controller 裡頭的值 -->
  <input type="text" ng-model="MyCtrl.value">
</div>

9. require

宣告該 directive 是否依賴其他 directive 的 controller 屬性
該 directive 可以在 link function 的地四個參數中取得依賴的 directive 的 controller function

宣告方式有四種:

  • (沒有前綴詞) - 在相同的 element 找對應的 directive,沒有找到會丟錯誤
  • ? - 在相同的 element 找對應的 directive,沒有找到會在 link function controller 的參數塞 null
  • ^ - 在相同跟上層 parent 找尋 directive,沒有找到會丟錯誤
  • ?^ - 在相同跟上層 parent 找尋 directive,沒有找到會在 link function controller 的參數塞 null

我目前實作 require 屬性的 directive 都是一定要找到依賴的 directive,所以幾乎沒有用加 ? 的版本。

範例用法:製作 tab 系列的 directives,需要兩種 directives。
tab 可以有多個,然後每個 tab 需要依賴 tabset 裡頭 controller 才分享資料跟溝通。
這時候在 tab 就需要 require tabset directive。

<tabset>
     <tab></tab>
     <tab></tab>
</tabset>

app.directive('tab’, function() {
  return {
    require: '^tabset',
   <...>
  });

完整範例:angular-foundation Tab directive

10. link
function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }

link function 大家應該很熟悉,專門來放操作 DOM 事情跟其他 directive 需要知道的邏輯。
之前看到有人會把對 DOM 操作、$watch 等邏輯放在 link,然後使用者互動邏輯放在 controller。
見仁見智,我通常都是 link function 裡頭有超過五個以上的 methods 才會想要拆開來~

11. compile
function compile(tElement, tAttrs, transclude) { ... }

compile 屬性跟 link 屬性只能兩選一。
因為 compile 規定要回傳 link function,所以假如 directive 有定義 compile 屬性,compile return 的值會覆寫你另外定義的 link function 。

compile 最常使用情境是當 template DOM 還沒 render 前,我們需要 scope 或 attributes 來生成 templates 需要的值。

範例:使用 compile 生成亂數的 id,讓畫面顯示
http://plnkr.co/edit/S93cquFdydntS0e1aDxT

app.directive('myDirective', function() {
    return {
      scope: {},
      compile: function () {
          // return link function 
          return {
            pre: function (scope, element, attrs) {

              var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
              for ( var i = 0; i < 5; i++ ) {
                scope.rId += possible.charAt(Math.floor(Math.random() * possible.length));
              }

            },
            post: function (scope) {

                scope.title = 'hello';

            }
          }
      },
      template:
          '<div>' +
            '<label for="{{rId}}" type="text">名稱</label>' +
            '<input id="{{rId}}" type="text" ng-model="title"/>' +
          '</div>'
    };
  });

個人很少使用到 compile 屬性,幾乎都是用 link + controller 完成 directive。


屬性呼叫順序:(假設 priority 相同)

parent compile -> children compile -> parent controller -> parent pre-link -> children controller -> children pre-link -> children post-link -> parent post-link

post-link 是最後一步驟,所以我們可以確保在裡面對 element 綁定事件是 ok 的。
(post-link 就是我們平常是用的 link function~)


上一篇
初談 directive - isolate scope
下一篇
初談 directive - 番外篇 - 傳送函式進 directive
系列文
我在前端 ng 時30

尚未有邦友留言

立即登入留言