2014-01-24 13 views
19

Ich habe eine Direktive, für die ich eine andere Direktive verwenden möchte. Ich habe versucht, Direktive-Controller zu verwenden, um dies zu erreichen.Controller, der von Direktive benötigt wird, kann nicht gefunden werden

Richtlinie würde man auf der gleichen Seite wie Richtlinie sitzen zwei und die Richtlinie ein Verfahren durch die Richtlinie Zweier-Controller ausgesetzt nennen würde:

Richtlinie 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(); 
       } 
      } 
     }; 
    }); 

Richtlinie zwei:

'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 
      } 
     }; 
    }); 

Datei, in der die beiden verwendet werden und als Geschwister eingerichtet:

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

Ich weiß, Dokumentation zu lesen Ich habe festgestellt, dass die Controller geteilt werden können, wenn die Direktiven auf dem gleichen Element sind, was mich denken lässt, dass ich dieses Problem falsch betrachten könnte. Kann mich jemand auf die richtige Spur bringen?

+0

Ass Sie sagten, um Controller zu teilen, müssten sie auf der gleichen Richtlinie sein. Sie könnten es einfacher haben, $ broadcast und $ emit zu verwenden. –

Antwort

7

Es gibt keine echte Möglichkeit, zwischen Geschwisterelementen in der Art zu kommunizieren, wie Sie hier vorgehen wollen. Die Anforderung funktioniert so, wie Sie sie eingerichtet haben, wenn die beiden Direktiven das gleiche Element sind.

Sie können dies jedoch nicht tun, da beide Ihrer Direktiven eine verknüpfte templateUrl haben, die Sie verwenden möchten, und Sie können nur eine pro Element haben.

Sie könnten Ihren HTML-Code etwas anders strukturieren, damit dies funktioniert. Im Grunde müssen Sie eine Anweisung in die andere setzen (übertragen) und require: '^videoClipDetails' verwenden. Das bedeutet, dass der Elternteil es finden wird. Ich habe eine Geige eingerichtet, um dies zu demonstrieren: http://jsfiddle.net/WwCvQ/1/

Dies ist der Code, der die Eltern, was Arbeit macht:

// 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', 

lassen Sie mich wissen, wenn Sie irgendwelche Fragen haben!

12

Aus der Angularjs documentation on directives

Wenn eine Richtlinie verwendet require, $compile werfen einen Fehler, wenn der angegebene Controller gefunden wird. Das Präfix ^ bedeutet, dass diese Direktive nach dem Controller auf seinen Eltern sucht (ohne das Präfix ^ würde die Direktive nur nach dem eigenen Element für den Controller suchen).

Also im Grunde, was Sie versuchen, mit Geschwister direkt kommunizieren zu kommunizieren, ist nicht möglich. Ich war auf dasselbe Problem gestoßen, wollte aber keinen Dienst zur Kommunikation nutzen. Was ich entwickelte, war eine Methode, eine Eltern-Direktive zu verwenden, um die Kommunikation zwischen ihren Kindern, die Geschwister sind, zu verwalten. Ich postete the example on github.

Was passiert ist, dass beide Kinder die Eltern (require: '^parentDirective') und ihre eigenen Controller benötigen, die beide in die Link-Funktion übergeben werden. Von dort kann jedes Kind eine Referenz auf den übergeordneten Controller und alle seine öffentlichen Methoden erhalten, als eine Art API.

Unten finden Sie eines der Kinder 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; 
     } 
    } 
} 

Hinweis, wie die in den require Array übergebenen Werte sind die Namen der Eltern-Richtlinie und der Name der derzeit geltenden Richtlinie. Diese sind dann beide in der link Funktion über den Parameter controllers erreichbar. Weisen Sie den Controller der übergeordneten Richtlinie als eine Eigenschaft des aktuellen untergeordneten Elements zu, und dann kann über die Eigenschaft in den Controllerfunktionen des untergeordneten Elements darauf zugegriffen werden.

Beachten Sie auch, wie in der Kinder-Richtlinie link Funktion ich eine initialize Funktion von der Kinder-Controller aufrufen. Hier ist ein Teil der Kommunikationsleitungen eingerichtet.

Ich bin im Grunde sagen, immer wenn Sie (Eltern-Direktive) erhalten eine Anfrage, ein Element zu bearbeiten, verwenden Sie diese Methode namens editItem, die eine item als Parameter verwendet. Hier

ist die Mutter Richtlinie

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; 
     } 
    } 
} 

Hier im Elternteil kann man sehen, dass die respondToEditsWith eine Methode als Parameter übernimmt und diesen Wert auf seine editMethod Eigenschaft zuordnet. Diese Eigenschaft wird aufgerufen, wenn die editItem -Methode des Controllers aufgerufen wird und das item-Objekt an sie übergeben wird. Dadurch wird die Methode editItem der untergeordneten Anweisung aufgerufen. Ebenso funktioniert das Speichern von Daten in umgekehrter Reihenfolge.

aktualisieren: By the way, hier ist a blog post on coderwall.com, wo ich die ursprüngliche Idee mit guten Beispielen von require und Controller-Optionen in den Richtlinien einsehen. Das heißt, seine empfohlene Syntax für das letzte Beispiel in diesem Beitrag funktionierte bei mir nicht, weshalb ich das Beispiel erstellt habe, auf das ich oben verwiesen habe.

+0

Vielen Dank Herr, ich bin seit ein paar Stunden stecken geblieben und versuche, diese Controller in einer Reihe von verwandten Direktiven zu implementieren. Die '^' Erklärung löste schnell mein Problem. Danke noch einmal. – fafafooey

Verwandte Themen