2014-01-24 1 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

Нет реального способа с требованием связываться между элементами-братьями так, как вы это пытаетесь сделать. Требование работает так, как вы настроили, если две директивы находятся на тот же элемент.

Вы не можете этого сделать, потому что обе ваши директивы имеют связанный шаблон urrl, который вы хотите использовать, и вы можете иметь только один элемент.

Вы можете структурировать свой 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 через параметр controllers. Назначьте контроллер родительской директивы как свойство текущего дочернего элемента, а затем его можно получить через функции контроллера ребенка через это свойство.

Также обратите внимание на функцию 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 дочерней директивы. Аналогично, сохранение данных работает одинаково в обратном порядке.

Update: Кстати, вот a blog post on coderwall.com где я получил оригинальную идею с хорошими примерами require и опций контроллера в директивах. Тем не менее, его рекомендуемый синтаксис для последнего примера в этом сообщении не сработал для меня, поэтому я создал приведенный выше пример.

+0

Спасибо большое, сэр, я застрял на пару часов, пытаясь (научиться угловатым) реализовать эти контроллеры в серии связанных директив. Объяснение «^» быстро решило мою проблему. Еще раз спасибо. – fafafooey

Смежные вопросы