2014-01-20 46 views
15

正常使用情況下角Angularjs:注入所需的指令控制器到控制器,而不是鏈接功能

如果你有父母的指令,並創建子指令,在父指令的控制器的方法和在你的子指令中需要父控制器。 Angular會將父控制器傳遞給你的子指令鏈接函數。

我的使用情況

我有一個使用情況下孩子的指令是另一指令父。我在中間的指令要求的頂部有指令。中間指令是底部最後一個指令所要求的。

在一個簡單的世界中,我可以爲中間指令創建一個鏈接方法和一個控制器。鏈接方法處理所有與頂部控制器和中間控制器傳遞到底部指令。

在我的情況下,中間指令的控制器中的方法必須調用父項中的方法,所以我需要中間控制器中的頂層控制器,而不是中間指令的鏈接函數!

問題

我怎麼能注入所需的控制器到控制器,而不是鏈接功能

angular.module('app').directive('top', function() { 
    return { 
     $scope: true, 
     templateUrl: "top.html", 
     controller: function() { 
      this.topMethod = function() { 
       // do something on top 
      } 
     } 
    } 
}); 

angular.module('app').directive('middle', function() { 
    return { 
     $scope: true, 
     templateUrl: "middle.html", 
     require: "^top", 
     controller: function($scope, $attrs, topController) { 
      this.middleMethod = function() { 
       // do something in the middle 

       // call something in top controller, this is the part that makes everything so complicated 
       topController.topMethod(); 
      } 
     } 
    } 
}); 

angular.module('app').directive('bottom', function() { 
    return { 
     $scope: true, 
     templateUrl: "bottom.html", 
     require: "^middle", 
     link: function(scope, element, attrs, middleController) { 
      $scope.bottomMethod = function() { 
       // do something at the bottom 

       // call something in the parent controller 
       middleController.middleMethod(); 
      } 
     } 
    } 
}); 

回答

13

實際上還有另一種方式,是更簡潔和is used by the angular ngModel itself

var parentForm = $element.inheritedData('$formController') || .... 

基本上它們使用控制器被存儲到指令DOM元素的數據屬性的事實。

仍然有點有線,但較少詳細和更容易理解。

我不明白爲什麼你不能將所需的控制器傳遞給指令控制器的注入局部。

+0

我想你可能已經鏈接到了錯誤的jsFiddle。這只是一個你好世界的例子。 – rob

+6

看來,還有更簡單的方法如何實現這一點: var parentForm = $ element.controller('form') – romario333

+1

我已經爲此和romario333的解決方案添加了一個演示:http://work.karlhorky。 com/frontend-tricks/angular-1-inject-required-directive-controller-into-directive-controller/ –

11

的問題是在編譯什麼順序指令和鏈接。假設我們有一個HTML的結構是這樣的:

<div top> 
    <div middle> 
     <div bottom></div> 
    </div> 
</div> 

和coresponding(simplyfied)有很多調試輸出的指令:

.directive('top', function() { 
    return { 
     controller : function($scope, $element, $attrs) { 
      this.topMethod = function() { 
       console.log('top method'); 
      } 
     }, 
     compile : function($element, $attrs) { 
      console.log('top compile'); 
      return { 
       pre : function($scope, $element, $attrs) { 
        console.log('top pre'); 
       }, 
       post : function($scope, $element, $attrs) { 
        console.log('top post'); 
       } 
      }; 
     } 
    } 
}) 

.directive('middle', function() { 
    return { 
     require : "^top", 
     controller : function($scope, $element, $attrs) { 
      this.middleMethod = function() { 
       console.log('middle method'); 
       $scope.topController.topMethod(); 
      } 
     }, 
     compile : function($element, $attrs) { 
      console.log('middle compile'); 
      return { 
       pre : function($scope, $element, $attrs, topController) { 
        console.log('middle pre'); 
        $scope.topController = topController; 
       }, 
       post : function($scope, $element, $attrs, topController) { 
        console.log('middle post'); 
       } 
      }; 
     }, 
    } 
}) 

.directive('bottom', function() { 
    return { 
     require : "^middle", 
     compile : function($element, $attrs) { 
      console.log('bottom compile'); 
      return { 
       pre : function($scope, $element, $attrs, middleController) { 
        console.log('bottom pre'); 
        middleController.middleMethod(); 
       }, 
       post : function($scope, $element, $attrs, middleController) { 
        console.log('bottom post'); 
       } 
      }; 
     } 
    } 
}) 

我們得到了以下的輸出:

top compile 
middle compile 
bottom compile 

top pre 
middle pre 
bottom pre 

middle method 
top method 

bottom post 
middle post 
top post 

正如我們先看到的那樣,調用編譯函數。然後調用預鏈接功能,然後調用後鏈接功能。編譯和預編譯將從上到下和後編從下到上。所以我們必須在預鏈接功能中設置控制器。

+0

我有同樣的想法,但首先執行控制器,所以topController在第一時間爲空。在topcontroller必須知道所有middleController的情況下,所以他們必須調用例如topController.addChild(this)我得到一個NullpointerException。我也不知道哪些其他副作用可能出現 – maklemenz

+0

@mklemenz你說「控制器先執行」是什麼意思? – michael

+0

首先控制器被執行,並且可能試圖使用這個時候未定義的topController。然後,鏈接方法將被執行,並將topController設置爲範圍,如果我不在控制器中首先得到一個異常。 – maklemenz

7

從romario333的評論摘自: 的乾淨的解決方案是簡單地使用

var topController = $element.controller('top') // pass directive name or controller name 

From the docs

控制器(名稱) - 獲取當前元素或其母公司的控制器。默認情況下,檢索與ngController指令相關的控制器。如果名稱是作爲camelCase指令名稱提供的,那麼將檢索該指令的控制器(例如'ngModel')。

$ element可以注入到您的指令控制器中。

相關問題