angular學習筆記(三十)-指令(10)-require和controller

本篇介紹指令的最後兩個屬性,require和controllerjavascript

當一個指令須要和父元素指令進行通訊的時候,它們就會用到這兩個屬性,什麼意思仍是要看栗子:css

html:html

<outer‐directive> 
    <inner‐directive></inner‐directive>
</outer‐directive> 

這裏有兩個指令,一個outer-directive指令元素,它裏面又有一個inner-directive指令元素.java

js:git

app.directive('outerDirective',function(){
    return {
        scope: {},
        restrict: 'AE',
        controller: function($scope,$compile,$http){
            this.addChild = function(nestedDirective){ //this指代controller   
            console.log('Got the message from nested directive' + nestedDirective.message);
            }
        }
    }
});    
app.directive('innerDirective',function(){
    return {
        scope: {},
        restrict: 'AE',
        require: '^?outerDirective',
        link: function(scope,elem,attrs,ctrl){
            //第四個參數是你require的controller實例
            scope.message = 'Hi, Parent directive';
            ctrl.addChild(scope);
        }
    };
});  

在父元素指令裏定義controller方法:github

function($scope,$compile,$http){   
   this.addChild = function(nestedDirective){ //this指代controller   
       console.log('Got the message from nested directive' + nestedDirective.message);
   }
}

controller方法是一個構造函數,能夠給它添加對象的方法(什麼是對象的方法看這裏:mvc-javascript-web-application / 01.MVC和類 / 1.建立類庫 / ex1.3(對象的方法).html).web

在子元素指令裏定義require屬性:require: '^?outerDirective',表示向外層尋找outerDirective指令,直到找到爲止.注意:向外層尋找,也包括了本身自己,也就是說,本身能夠尋找到本身身上的其它指令.bootstrap

'?'的做用是若是找不到也不會報錯.數組

定義了require屬性後,link函數的第四個參數ctrl就是require到的指令的controller方法的實例.因此ctrl就有了addChild方法了. mvc

 

下面看一個難一點的栗子:

angular學習筆記(三十)-指令(9)-一個簡單的指令示例這個栗子是單個子菜單的展開收起,下面使用require和controller,來擴展這個應用,改爲多個菜單,要求點擊某個菜單的時候展開此菜單,而其他菜單都收起:

以下過程:

html:

<!DOCTYPE html>
<html ng-app="accordionModule">
<head>
  <title>20.10 指令-accordion</title>
  <meta charset="utf-8">
  <link href="../bootstrap.css" rel="stylesheet">
  <script src="../angular.min.js"></script>
  <script type="text/ng-template" id="vertical.html">
    <div class="btn-group-vertical" ng-transclude>
    </div>
  </script>
  <script type="text/ng-template" id="text.html">
    <div class="btn-group">
      <button class="btn btn-default dropdown-toggle" type="button" ng-click="toggle()">{{title}}<span class="caret"></span></button>
      <ul class="dropdown-menu" ng-show="ifShow" ng-transclude></ul>
    </div>
  </script>
  <script src="script.js"></script>
  <style type="text/css">
    body{
      padding:40px
    }
  </style>
</head>
<body>
  <div ng-controller="accordionCtrl">
    <accordion>
      <expander ng-repeat="list in lists" my-title="{{list.title}}">
        <li ng-repeat="content in list.contents">
          <a href="">{{content}}</a>
        </li>
      </expander>
    </accordion>
  </div>
</body>
</html>

js:

/*20.10 指令*/
var accordionModule = angular.module('accordionModule',[]);
accordionModule.controller('accordionCtrl',function($scope){
    $scope.lists = [
        {title:'標題1',contents:['bunny1','cat1','dog1']},
        {title:'標題2',contents:['bunny2','cat2','dog2']},
        {title:'標題3',contents:['bunny3','cat3','dog3']},
        {title:'標題4',contents:['bunny4','cat4','dog4']},
        {title:'標題5',contents:['bunny5','cat5','dog5']},
        {title:'標題6',contents:['bunny6','cat6','dog6']},
        {title:'標題7',contents:['bunny7','cat7','dog7']},
        {title:'標題8',contents:['bunny8','cat8','dog8']}
    ]
});
accordionModule.directive('accordion',function(){
    return {
        restrict:'EA',
        replace:true,
        templateUrl:'vertical.html',
        transclude:true,
        controller:function(){
            this.expanders = [];
            this.closeAll = function(scope){
                angular.forEach(this.expanders,function(expander){
                    if(scope!=expander)
                    expander.ifShow = false;
                })
            };
            this.addExpander = function(scope){
                this.expanders.push(scope)
            }
        }
    }
});
accordionModule.directive('expander',function(){
    return {
        restrict:'EA',
        replace:true,
        templateUrl:'text.html',
        transclude:true,
        scope:{title:'@myTitle'},
        require:'^?accordion',
        link:function(scope,ele,attrs,ctrl){
            scope.ifShow = false;
            ctrl.addExpander(scope);
            scope.toggle = function(){
                ctrl.closeAll(scope);
                scope.ifShow = !scope.ifShow;
            }
        }
    }
});

下面來解釋這個應用:

1. accordion指令的controller的實例也就是link函數的第四個參數ctrl

2. 將expander指令進行ng-repeat,渲染出多個子菜單.

3. 因爲這些子菜單是互相有關聯而非獨立存在的,因此將他們放在一個accordion指令中.

4. 綁定數據模型都和單獨的expander同樣,惟一不一樣的是: 

    1) link函數中調用ctrl的addExpander方法,將每一個expander的獨立scope壓入ctrl的expanders數組中.

    2) toggle()方法,它調用了accordion指令的controller的實例的方法.收起除了當前點擊項之外其他的菜單.

5. 注意ctrl是惟一的ctrl,而不是每次都實例化出一個新的實例.雖然有多個expander,可是它的ctrl指向的是同一個實例,因此expanders數組是惟一的.

6. 這裏expanders數組裏存放是每一個expander的scope,爲何是scope而不是element呢? 由於closeAll方法須要修改指令獨立做用域下的ifShow的,因此這裏數組裏存放scope比較好寫.

完整代碼: https://github.com/OOP-Code-Bunny/angular/blob/master/OREILLY/20.10%20%E6%8C%87%E4%BB%A4.html

             https://github.com/OOP-Code-Bunny/angular/blob/master/OREILLY/script.js

相關文章
相關標籤/搜索