5

Ich habe derzeit eine Richtlinie, die ist mit Eigenschaften aus dem übergeordneten Controllers Umfang mit:Zugriff geordneten Bereichs in der Richtlinie, wenn controllerAs

.controller('MainCtrl', function($scope) { 
    $scope.name = 'My Name'; 
}) 

.directive('myDirective', function() { 
    return { 
    scope: true, 
    controller: function($scope) { 
     console.log($scope.name); // logs 'My Name' 
    } 
    }; 
}) 

Jetzt bewege ich mich über zu controllerAs Syntax in meinem Controller, aber ich weiß nicht Ich weiß, wie ich einen Verweis auf das Controller-Objekt im Controller meiner Direktive bekomme.

.controller('MainCtrl', function() { 
    var vm = this; 
    vm.name = 'My Name'; 
}) 

.directive('myDirective', function() { 
    return { 
    scope: true, 
    controller: function($scope) { 
     console.log(vm.name); // logs 'Undefined' 
    } 
    }; 
}) 

Hier a plunkr das Problem veranschaulicht.

Ich fand auch , die versucht, etwas ähnliches zu erklären, aber in diesem Fall ist er nur den gleichen Controller wiederverwenden.

Antwort

9

Wenn Sie die ControllerAs Syntax verwenden, wird eine Eigenschaft auf dem $scope Objekt erstellt, die ein Alias ​​ist auf Ihre Regler. zum Beispiel, ng-controller="MainCtrl as vm" gibt Ihnen $scope.vm. $scope ist im HTML enthalten, daher ist der Zugriff auf vm.name im HTML-Code derselbe wie der Zugriff auf $scope.vm.name in JavaScript.

In der Steuerung können Sie entweder auf this.name oder $scope.vm.name zugreifen, sie wären funktional gleichwertig. In andere Controller, würde this auf diesen spezifischen Controller beziehen, und somit this.name würde nicht funktionieren.

Daher können Sie in diesem Fall auf die gewünschte Eigenschaft im Controller der Direktive zugreifen, indem Sie verwenden. http://plnkr.co/edit/WTJy7LlB7VRJzwTGdFYs?p=preview

Sie werden jedoch wahrscheinlich auch die Syntax von ControllerAs mit der Anweisung verwenden wollen; In diesem Fall empfehle ich, anstatt vm für die Controller-Namen zu verwenden, einen eindeutigen Namen zu verwenden, mit dem Sie feststellen können, auf welchen Controller Sie sich beziehen. MainCtrl as main, und dann unter Bezugnahme auf main.name wird viel klarer.

Ich empfehle jedoch, einen isolieren Bereich zu verwenden, da es Ihnen ermöglicht, die Notwendigkeit, $scope in Ihre Richtlinien zu injizieren, vollständig zu beseitigen und Ihre Richtlinie in sich abgeschlossen und wiederverwendbar zu machen.

Seitennotiz, bindToController: true, tut nichts, wenn Sie kein isolieren Bereich verwenden; Wenn Sie mit einem isolieren Bereich verwenden, erstellt es Eigenschaften auf dem isolierten Controller, um den übergebenen Bereich zu entsprechen, so dass Sie auf die übergebenen Werte zugreifen können, ohne $scope zu benötigen.

+0

Das habe ich gebraucht - danke. Ich dachte nicht, dass die Beziehung von 'vm' in der html wirklich' $ scope.vm' ist, was bedeutet, dass ich immer noch auf die Eigenschaften in der Kette zugreifen kann. Ich mag auch den Ratschlag zum Thema "Isolate Scope" - ich dachte, isolate scopes würden nur verwendet, um Interaktionen zu vermeiden, anstatt explizit zu sein. – diplosaurus

+0

Um meinen Eltern-Controller in der Direktive mit ControllerAs zu verwenden, kann ich $ scope.vm verwenden ... aber dann harcodiere ich vm in meiner Direktive ... und lasse sagen, ob ich es auch woanders benutzen möchte muss sicherstellen, dass der Alias ​​meines übergeordneten Controllers vm..anderewise wird es nicht funktionieren .. Gibt es irgendwelche Arbeit für diese ..? –

+0

@rishitiwari im Allgemeinen sollten Sie danach streben, agnostische Anweisungen zu erstellen, die keine Abhängigkeit von ihrem übergeordneten Host haben. Statt auf den übergeordneten Controller zuzugreifen, sollten Sie die Daten, mit denen Ihre Anweisung arbeitet, als Argumente akzeptieren. – Claies

2

Eine Möglichkeit besteht darin, die $scope Kette zu durchlaufen, bis Sie vm finden.

app.directive('myDir', function() { 
    return { 
    restrict: 'E', 
    scope: true, 
    template: '<div>my directive</div>', 
    bindToController: true, 
    controller: function($scope) { 
     console.log($scope.name2); // logs 'bound to the controller scope' 
     console.log($scope.$parent.vm.name); // logs 'bound to the controller vm' 
    } 
    }; 
}); 

Allerdings kann dies sehr spröde sein und es riecht ein bisschen nach.

Ein ausgefeilterer und durchdachterer Ansatz besteht darin, eine Eigenschaft des Bereichs Ihres Controllers über ein übergebenes Argument an Ihre Anweisung zu binden.

HTML:

<my-dir name="vm.name" /> 

JS:

app.directive('myDir', function() { 
    return { 
    restrict: 'E', 
    scope: { 
     name: "=" 
    }, 
    template: '<div>my directive</div>', 
    bindToController: true, 
    controller: function($scope) { 
     console.log($scope.name); // logs 'bound to the controller vm' 
    } 
    }; 
}); 

Siehe plunkr

+0

So funktioniert das, obwohl es ein wenig deprimierend ist, dass jede Eigenschaft auf der äußeren 'vm' manuell über ein Attribut an die Direktive gebunden werden muss, das könnte unordentlich werden. Die Sache, die ich nicht verstehe, ist, warum ich einen Isolate-Bereich verwenden muss, ein geerbter sollte mir immer noch einen Zugriff auf die Eigenschaft geben. – diplosaurus

+0

Sie könnten den gesamten Umfang anstelle einer einzelnen Eigenschaft übergeben, wenn Sie dies wünschen. Das würde erreichen, was Sie brauchen, obwohl ich vorsichtig sein würde, um so viel Inhalt von Ihrem Controller Ihrer Richtlinie auszusetzen. Zu viel Belichtung verbindet Ihre Komponenten stark und verringert deren Wiederverwendbarkeit (was eines der aktuellen Probleme bezüglich Scope/vm/Angular 1.x ist und eines der Dinge, die wir am meisten in Angular 2 sehen werden). –

+0

Anstatt den gesamten Bereich zu übergeben, können Sie nur die Alias-Eigenschaft übergeben. Auf diese Weise können Sie in Ihrem ursprünglichen Bereich mit '$ scope' noch etwas definieren und diese Eigenschaft wird nicht in der Direktive –

Verwandte Themen