2014-01-24 36 views
19

我有一個指令,我希望其他指令能夠調用。我一直試圖使用指令控制器來嘗試實現這一點。指令所需的控制器無法找到

指令人會坐在同一頁上指示兩個,指令一個會叫的指令二的控制器暴露方法:

指令1:

'use strict'; 
angular.module('angularTestApp') 
    .directive('fileLibrary', function() { 
     return { 
      templateUrl: 'views/manage/file_library/file-library.html', 
      require: 'videoClipDetails', 
      restrict: 'AE', 
      link: function postLink(scope, element, attrs, videClipDetailsCtrl) { 
       scope.doSomethingInVideoClipDirective = function() { 
        videClipDetailsCtrl.doSomething(); 
       } 
      } 
     }; 
    }); 

指令二:

'use strict'; 
angular.module('angularTestApp') 
    .directive('videoClipDetails', function() { 
     return { 
      templateUrl: 'views/video_clip/video-clip-details.html', 
      restrict: 'AE', 
      controller: function($scope, $element) { 
       this.doSomething = function() { 
        console.log('I did something'); 
       } 
      }, 
      link: function postLink(scope, element, attrs) { 
       console.log('videoClipDetails directive'); 
       //start the element out as hidden 
      } 
     }; 
    }); 

文件,其中兩個被使用和設置爲兄弟姐妹:

<div> 
    <div video-clip-details></div> 
    <!-- main component for the file library --> 
    <div file-library></div> 
</div> 

我知道,閱讀文檔,我拿起了控制器可以當指令是相同的元素,這讓我覺得我可能會尋找這個問題的錯誤的方式上進行共享。任何人都可以讓我走上正軌嗎?

+0

你說,分享控制器他們需要在同一個指令。您可能更容易使用$ broadcast和$ emit。 –

回答

7

在您嘗試在此處執行的方式中,沒有要求在兄弟元素之間進行通信的真正方法。如果兩個指令都在相同元素上,則需求將按照您設置的方式工作。

你不能做到這一點然而,由於雙方您的指令有您要使用的相關templateUrl,你只能有每個元素之一。

你可以稍微不同地構造你的html,以允許它工作。您基本上需要將一個指令放入另一個指令(transcluded)中並使用require: '^videoClipDetails'。這意味着它會尋找父母來找到它。 我已經建立了一個小提琴證明這一點:http://jsfiddle.net/WwCvQ/1/

這是使父的事工作代碼:

// In videoClipDetails 
template: '<div>clip details<div ng-transclude></div></div>', 
transclude: 'true', 
... 
// in markup 
<div video-clip-details> 
    <div file-library></div> 
</div> 
// in fileLibrary 
require: '^videoClipDetails', 

讓我知道如果您有任何問題!除非指定控制器發現

12

從angular.js documentation on directives

當指令使用require$compile將拋出一個錯誤。該^前綴意味着該指令對在其父母控制(不^前綴,該指令看起來只是自己的元素上的控制器)搜索。

所以基本上你正在嘗試與兄弟姐妹直接溝通是不可能的。我遇到了同樣的問題,但我不想使用服務進行通信。我想出了用父母的指令來管理它的孩子,這是兄弟之間的通信的方法。我發佈the example on github

發生什麼事情是兩個孩子都需要父母(require: '^parentDirective')和他們自己的控制器,他們都被傳遞到鏈接函數中。從那裏,每個孩子都可以獲得對父控制器及其所有公共方法的引用,作爲各種API。

下面是孩子itemEditor

function itemEditor() { 
    var directive = { 
     link: link, 
     scope: {}, 
     controller: controller, 
     controllerAs: 'vm', 
     require: ['^itemManager', 'itemEditor'], 
     templateUrl: 'app/scripts/itemManager/itemManager.directives.itemEditor.html', 
     restrict: 'A' 
    }; 

    return directive; 

    function link(scope, element, attrs, controllers) { 
     var itemManagerController = controllers[0]; 
     var itemEditorController = controllers[1]; 

     itemEditorController.itemManager = itemManagerController; 

     itemEditorController.initialize(); 
    } 

    function controller() { 
     var vm = this; 

     // Properties 
     vm.itemManager = {}; 
     vm.item = { id: -1, name: "", size: "" }; 

     // Methods 
     vm.initialize = initialize; 
     vm.updateItem = updateItem; 
     vm.editItem = editItem; 

     // Functions 
     function initialize() { 
      vm.itemManager.respondToEditsWith(vm.editItem); 
     } 

     function updateItem() { 
      vm.itemManager.updateItem(vm.item); 
      vm.item = {}; 
     } 

     function editItem(item) { 
      vm.item.id = item.id; 
      vm.item.name = item.name; 
      vm.item.size = item.size; 
     } 
    } 
} 

注意傳遞到require數組中的值是如何父指令的名稱和當前指令的名字之一。這些都可以通過參數在link函數中訪問。將父指令的控制器分配爲當前子元素的屬性,然後可以通過該屬性在子元素的控制器功能中對其進行訪問。

另請注意,兒童指令的link函數如何從子控制器調用initialize函數。這是通信線路的一部分建立的地方。

我基本上是說,只要你(家長指令)收到一個編輯項目的請求,使用這個我的名字爲editItem的方法,它需要一個item作爲參數。

這裏是父母指令

function itemManager() { 
    var directive = { 
     link: link, 
     controller: controller, 
     controllerAs: 'vm', 
     templateUrl: 'app/scripts/itemManager/itemManager.directives.itemManager.html', 
     restrict: 'A' 
    }; 

    return directive; 

    function link(scope, element, attrs, controller) { 

    } 

    function controller() { 
     var vm = this; 

     vm.updateMethod = null; 
     vm.editMethod = null; 

     vm.updateItem = updateItem; 
     vm.editItem = editItem; 
     vm.respondToUpdatesWith = respondToUpdatesWith; 
     vm.respondToEditsWith = respondToEditsWith; 

     function updateItem(item) { 
      vm.updateMethod(item); 
     } 

     function editItem(item) { 
      vm.editMethod(item); 
     } 

     function respondToUpdatesWith(method) { 
      vm.updateMethod = method; 
     } 

     function respondToEditsWith(method) { 
      vm.editMethod = method; 
     } 
    } 
} 

在這裏,你可以看到respondToEditsWith採用的方法作爲參數和值分配給它的editMethod財產父。只要調用控制器的editItem方法並將item對象傳遞給該屬性,就會調用該屬性,從而調用子指令的editItem方法。同樣,保存數據的方式相反。

更新:順便說一下,這裏是a blog post on coderwall.com在那裏我得到了與在指令控制器選項的require很好的例子了原來的想法。也就是說,他推薦的那篇文章中最後一個例子的語法不適合我,這就是爲什麼我創建了上面我參考的例子。

+0

非常感謝主席先生,我一直堅持了幾個小時試圖(在學習角度的同時)在一系列相關指令中實現這些控制器。 '^'解釋很快解決了我的問題。再次感謝。 – fafafooey

相關問題