2013-03-28 4 views
79

Kann mir jemand sagen, wie man einen Controller aus einer Direktive in eine andere angularJS-Direktive einbaut. zum Beispiel habe ich den folgenden CodeWie benötigt man einen Controller in einer angularjs-Direktive?

var app = angular.module('shop', []). 
config(['$routeProvider', function ($routeProvider) { 
    $routeProvider.when('/', { 
     templateUrl: '/js/partials/home.html' 
    }) 
     .when('/products', { 
     controller: 'ProductsController', 
     templateUrl: '/js/partials/products.html' 
    }) 
     .when('/products/:productId', { 
     controller: 'ProductController', 
     templateUrl: '/js/partials/product.html' 
    }); 
}]); 

app.directive('mainCtrl', function() { 
    return { 
     controller: function ($scope) {} 
    }; 
}); 

app.directive('addProduct', function() { 
    return { 
     restrict: 'C', 
     require: '^mainCtrl', 
     link: function (scope, lElement, attrs, mainCtrl) { 
      //console.log(cartController); 
     } 
    }; 
}); 

Durch alle Konto sollte ich in der Lage sein, den Controller in der addProduct Richtlinie zugreifen, aber ich bin es nicht. Gibt es einen besseren Weg, dies zu tun?

+4

"require" stellt das Vorhandensein einer anderen Direktive sicher und schließt dann seinen Controller ein. '^ required' prüft zusätzlich zum aktuellen Element Elemente über der aktuellen. Sie müssen also die beiden Direktiven zusammen verwenden, damit dies funktioniert. Andernfalls definieren Sie einfach einen Controller mit 'app.controller' und verwenden ihn dann in beiden Direktiven. Wie auch immer, können Sie dies zusammen mit Ihrem HTML-Code in einen einfachen Plunker einfügen? –

+0

das war die Antwort –

Antwort

180

Ich hatte Glück und beantwortete dies in einem Kommentar zu der Frage, aber ich packe eine vollständige Antwort der Vollständigkeit halber und so können wir diese Frage als "Beantwortet" markieren.


Es hängt davon ab, was Sie erreichen möchten, indem Sie einen Controller freigeben; Sie können entweder den gleichen Controller verwenden (obwohl verschiedene Instanzen vorhanden sind) oder Sie können dieselbe Controllerinstanz verwenden.

app.controller('MyCtrl', function ($scope) { 
    // do stuff... 
}); 

app.directive('directiveOne', function() { 
    return { 
    controller: 'MyCtrl' 
    }; 
}); 

app.directive('directiveTwo', function() { 
    return { 
    controller: 'MyCtrl' 
    }; 
}); 

Jede Richtlinie wird eine eigene Instanz des Controllers erhalten,:

Teile eines Controller

zwei Richtlinien die gleiche Steuerung, indem man die gleiche Methode, um zwei Richtlinien, wie so verwenden können, aber das erlaubt Ihnen, die Logik zwischen so vielen Komponenten zu teilen, wie Sie wollen.

ein Controller erforderlich

Wenn Sie die gleiche Instanz eines Controllers teilen möchten, dann nutzen Sie require.

require gewährleistet die Anwesenheit einer anderen Richtlinie und dann deren Steuerung enthält als Parameter für die Link-Funktion. Wenn Sie also zwei Direktiven für ein Element haben, kann Ihre Anweisung das Vorhandensein der anderen Direktive erfordern und Zugriff auf ihre Controller-Methoden erhalten. Ein häufiger Anwendungsfall hierfür ist ngModel.

^require, mit dem Zusatz des Caret, überprüft Elemente über Direktive zusätzlich zu dem aktuellen Element, um zu versuchen, die andere Direktive zu finden. Auf diese Weise können Sie komplexe Komponenten erstellen, in denen "Unterkomponenten" über ihren Controller mit der übergeordneten Komponente kommunizieren können. Beispiele können Registerkarten enthalten, in denen jedes Fenster mit den gesamten Registerkarten kommunizieren kann, um das Wechseln zu ermöglichen. ein Akkordeon-Set könnte sicherstellen, dass immer nur eines offen ist; usw.

In beiden Fällen müssen Sie die beiden Anweisungen zusammen verwenden, damit dies funktioniert. require ist eine Art der Kommunikation zwischen Komponenten.

prüfen den Leitfaden Seite von Richtlinien für weitere Informationen aus: http://docs.angularjs.org/guide/directive

+0

danke für die Antwort, die es definitiv getan hat. –

+2

Ist es möglich, einen Geschwister-Direktiven-Controller zu benötigen? Grundsätzlich muss ich die gleiche Instanz eines Controllers oder Dienstes zwischen Geschwister-Direktiven (wie in DOM-Geschwistern, nicht auf dem gleichen DOM-Element) teilen, die mit ng-repeat wiederholt werden. Stellen Sie sich vor, dass jedes wiederholte Element eine Direktive hat, die einen gemeinsamen Status oder Logik zwischen ihnen benötigt. – CMCDragonkai

+2

@CMCDragonkai Es gibt keine Möglichkeit, das zu tun, aber es gibt zwei übliche Wege, dasselbe zu erreichen. Die erste ist, wenn die Geschwister alle den gleichen "Typ" haben, dann kann das Element über dem ngRepeat wie eine Container-Direktive sein und alle Unterelemente können dann stattdessen diese Direktive benötigen, wobei alle denselben Controller benutzen. Die häufigere Lösung - und oft kanonischer - ist die Verwendung eines gemeinsamen Dienstes. Können Sie näher erläutern, was diese Geschwister tun und was sie teilen müssen? –

27

Es gibt eine Antwort von Mark Rajcok hier gut Stackoverflow ist:

AngularJS directive controllers requiring parent directive controllers?

mit einem Link zu diesem sehr klar jsFiddle: http://jsfiddle.net/mrajcok/StXFK/

<div ng-controller="MyCtrl"> 
    <div screen> 
     <div component> 
      <div widget> 
       <button ng-click="widgetIt()">Woo Hoo</button> 
      </div> 
     </div> 
    </div> 
</div> 

JavaScript

var myApp = angular.module('myApp',[]) 

.directive('screen', function() { 
    return { 
     scope: true, 
     controller: function() { 
      this.doSomethingScreeny = function() { 
       alert("screeny!"); 
      } 
     } 
    } 
}) 

.directive('component', function() { 
    return { 
     scope: true, 
     require: '^screen', 
     controller: function($scope) { 
      this.componentFunction = function() { 
       $scope.screenCtrl.doSomethingScreeny(); 
      } 
     }, 
     link: function(scope, element, attrs, screenCtrl) { 
      scope.screenCtrl = screenCtrl 
     } 
    } 
}) 

.directive('widget', function() { 
    return { 
     scope: true, 
     require: "^component", 
     link: function(scope, element, attrs, componentCtrl) { 
      scope.widgetIt = function() { 
       componentCtrl.componentFunction(); 
      }; 
     } 
    } 
}) 


//myApp.directive('myDirective', function() {}); 
//myApp.factory('myService', function() {}); 

function MyCtrl($scope) { 
    $scope.name = 'Superhero'; 
} 
+4

Für mich war es das Beispiel von Mark Rajcok, das am meisten darauf achtete, wie die Controller-Methoden erstellt werden. Normalerweise werden Controller-Methoden angezeigt, die mit $ scope.methodName = function() {...} erstellt wurden. Damit dies jedoch funktioniert, müssen Sie this.methodName für die Methoden verwenden, auf die Sie zugreifen möchten. Das habe ich zuerst nicht bemerkt. – coblr