Подтвердить что ты не робот

Невозможно найти контроллер, требуемый по директиве

У меня есть директива о том, что мне нужна другая директива, чтобы иметь возможность позвонить. Я пытаюсь использовать контрольные контроллеры, чтобы попытаться достичь этого.

Директива будет сидеть на той же странице, что и директива two, а директива - вызывать методы, выставленные директивой два контроллера:

Директива 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>

Я знаю документацию для чтения. Я понял, что контроллеры могут использоваться совместно, когда директивы находятся на одном элементе, что заставляет меня думать, что я, возможно, неправильно рассматриваю эту проблему. Может ли кто-нибудь поставить меня на правильный путь?

4b9b3361

Ответ 1

В документации angular.js по директивам

Когда директива использует require, $compile выдаст ошибку, если указанный контроллер не найден. Префикс ^ означает, что эта директива ищет контроллер у его родителей (без префикса ^, директива будет искать контроллер только для своего собственного элемента).

Так что в основном то, что вы пытаетесь сделать с тем, что братья и сестры напрямую общаются, невозможно. Я столкнулся с этой проблемой, но я не хотел использовать службу для общения. То, что я придумал, - это метод использования родительской директивы для управления связью между ее дочерними элементами, которые являются братьями и сестрами. Я отправил пример в 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, тем самым вызывая метод child tive editItem. Аналогично, сохранение данных работает одинаково в обратном порядке.

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

Ответ 2

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

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

Вы можете структурировать свой 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',

сообщите мне, если у вас есть вопросы!