angularjs watch




'this' vs $ scope in AngularJS-Controllern (5)

Im Abschnitt "Create Components" auf der Homepage von AngularJS gibt es folgendes Beispiel:

controller: function($scope, $element) {
  var panes = $scope.panes = [];
  $scope.select = function(pane) {
    angular.forEach(panes, function(pane) {
      pane.selected = false;
    });
    pane.selected = true;
  }
  this.addPane = function(pane) {
    if (panes.length == 0) $scope.select(pane);
    panes.push(pane);
  }
}

Beachten Sie, dass die select Methode zu $scope hinzugefügt wird, aber die addPane Methode hinzugefügt this . Wenn ich es in $scope.addPane , bricht der Code ab.

Die Dokumentation besagt, dass es tatsächlich einen Unterschied gibt, aber nicht erwähnt, was der Unterschied ist:

Frühere Versionen von Angular (vor 1.0 RC) erlaubten es, this austauschbar mit der $scope Methode zu verwenden, dies ist jedoch nicht mehr der Fall. Innerhalb von Methoden, die für den Geltungsbereich definiert sind, sind this und $scope austauschbar (angle setzt this auf $scope ), ansonsten jedoch nicht in Ihrem Controller-Konstruktor.

Wie funktioniert this und $scope in AngularJS Controllern?


"Wie funktioniert this und $scope in AngularJS Controllern?"

Kurze Antwort :

  • this
    • Wenn die Controller-Konstruktorfunktion aufgerufen wird, ist this der Controller.
    • Wenn eine für ein $scope Objekt definierte Funktion aufgerufen wird, ist this der "Gültigkeitsbereich, wenn die Funktion aufgerufen wurde". Dies kann (oder darf nicht!) Der $scope , für den die Funktion definiert ist. Innerhalb der Funktion sind this und $scope möglicherweise nicht identisch.
  • $scope
    • Jedem Controller ist ein $scope Objekt zugeordnet.
    • Eine Controller (Konstruktor) -Funktion ist verantwortlich für das Festlegen von Modelleigenschaften und Funktionen / Verhalten auf dem zugehörigen $scope .
    • Nur Methoden, die für dieses $scope Objekt definiert sind (und übergeordnete Scope-Objekte, wenn prototypische Vererbung im Spiel ist), sind über die HTML / View zugänglich. ZB von ng-click , Filtern, etc.

Lange Antwort :

Eine Controller-Funktion ist eine JavaScript-Konstruktorfunktion. Wenn die Konstruktorfunktion ausgeführt wird (z. B. wenn eine Ansicht geladen wird), wird this (dh der "Funktionskontext") auf das Steuerungsobjekt gesetzt. Also in der Controller-Konstruktor-Funktion "tabs", wenn die addPane-Funktion erstellt wird

this.addPane = function(pane) { ... }

Es wird auf dem Controller-Objekt erstellt, nicht auf $ scope. Ansichten können die Funktion addPane nicht sehen - sie haben nur Zugriff auf Funktionen, die in $ scope definiert sind. Mit anderen Worten, im HTML funktioniert das nicht:

<a ng-click="addPane(newPane)">won't work</a>

Nachdem die Steuerungskonstruktorfunktion "Tabs" ausgeführt wurde, haben wir Folgendes:

Die gestrichelte schwarze Linie zeigt die prototypische Vererbung an - ein isolierter Bereich erbt prototypisch von Scope . (Er erbt nicht prototypisch den Gültigkeitsbereich, in dem die Anweisung im HTML-Code gefunden wurde.)

Nun möchte die Link-Funktion der Fenster-Direktive mit der Tabs-Direktive kommunizieren (was wirklich bedeutet, dass sie die Tabs beeinflussen muss, isoliere $ scope in irgendeiner Weise). Ereignisse könnten verwendet werden, aber ein anderer Mechanismus besteht darin, dass die Fensteranweisung den Registerkarten-Controller require . (Es scheint keinen Mechanismus für die Bereichsanweisung zu geben require die Registerkarten $ scope benötigt.)

Also, das wirft die Frage auf: Wenn wir nur Zugriff auf den Tabs-Controller haben, wie erhalten wir Zugriff auf die Tabs isolieren $ scope (was ist das, was wir wirklich wollen)?

Nun, die rote gepunktete Linie ist die Antwort. Der "Bereich" der AddPane () - Funktion (ich verweise hier auf den Funktionsumfang / Schließungen von JavaScript) gibt der Funktion Zugriff auf die Registerkarten isolieren $ scope. Dh, addPane () hat Zugriff auf die "Registerkarten IsolateScope" im obigen Diagramm wegen einer Schließung, die erstellt wurde, als addPane () definiert wurde. (Wenn wir stattdessen addPane () auf den Registern $ scope object definieren würden, hätte die Fensteranweisung keinen Zugriff auf diese Funktion und hätte daher keine Möglichkeit, mit den Registerkarten $ scope zu kommunizieren.)

Um den anderen Teil Ihrer Frage zu beantworten: how does $scope work in controllers? :

Innerhalb von Funktionen, die in $ scope definiert sind, wird this auf "den $ scope in effect wo / wann die Funktion aufgerufen wurde" gesetzt. Angenommen, wir haben den folgenden HTML-Code:

<div ng-controller="ParentCtrl">
   <a ng-click="logThisAndScope()">log "this" and $scope</a> - parent scope
   <div ng-controller="ChildCtrl">
      <a ng-click="logThisAndScope()">log "this" and $scope</a> - child scope
   </div>
</div>

Und die ParentCtrl (ausschließlich) hat

$scope.logThisAndScope = function() {
    console.log(this, $scope)
}

Wenn Sie auf den ersten Link klicken, wird angezeigt, dass this und $scope identisch sind, da " der beim Aufruf der Funktion ParentCtrl Gültigkeitsbereich" der mit der ParentCtrl .

Wenn Sie auf die zweite Verknüpfung klicken, wird this ChildCtrl und der $scope ist nicht derselbe, da " der Gültigkeitsbereich, der beim Aufruf der Funktion ChildCtrl war ", der mit der ChildCtrl . Hier ist ChildCtrl der $scope von ChildCtrl gesetzt. Innerhalb der Methode ist $scope immer noch der $ scope von ParentCtrl .

Fiddle

Ich versuche, dies nicht innerhalb einer Funktion zu verwenden, die in $ scope definiert ist, da es verwirrend wird, welcher $ scope betroffen ist, insbesondere wenn man bedenkt, dass ng-repeat, ng-include, ng-switch und directions ihre eigenen untergeordneten Bereiche erstellen können .


Frühere Versionen von Angular (vor 1.0 RC) erlaubten es, dies austauschbar mit der $ scope-Methode zu verwenden, dies ist jedoch nicht mehr der Fall. Innerhalb von Methoden, die für den Geltungsbereich definiert sind, sind dieser und $ scope austauschbar (angle setzt dies auf $ scope), ansonsten jedoch nicht in Ihrem Controller-Konstruktor.

Um dieses Verhalten zurückzubringen (weiß jemand, warum wurde es geändert?) Können Sie hinzufügen:

return angular.extend($scope, this);

am Ende Ihrer Controller-Funktion (vorausgesetzt, $ scope wurde in diese Controller-Funktion injiziert).

Dies hat einen schönen Effekt des Zugriffs auf den Parent-Bereich über das Controller-Objekt, das Sie in Child mit require: '^myParentDirective'


Der Grund dafür, dass 'addPane' zugewiesen wurde, liegt an der <pane> -Direktive.

Die pane Direktive require: '^tabs' , die das Tabs-Controller-Objekt aus einer übergeordneten Direktive in die Link-Funktion einfügen.

addPane ist diesem zugewiesen, sodass die addPane es sehen kann. Dann in der pane Link-Funktion, addPane ist nur eine Eigenschaft des tabs Controller, und es ist nur tabsControllerObject.addPane. Die Verknüpfungsfunktion der Fensterrichtlinie kann also auf das Tabs-Controller-Objekt zugreifen und somit auf die addPane-Methode zugreifen.

Ich hoffe, meine Erklärung ist klar genug. Es ist schwer zu erklären.


Ich empfehle Ihnen, den folgenden Beitrag zu lesen: http://codetunnel.io/angularjs-controller-as-or-scope/

Es beschreibt sehr gut die Vorteile der Verwendung von "Controller as", um Variablen gegenüber "$ scope" offenzulegen.

Ich weiß, dass Sie speziell nach Methoden und nicht nach Variablen gefragt haben, aber ich denke, dass es besser ist, sich an eine Technik zu halten und konsistent zu sein.

Also, meiner Meinung nach, wegen der Variablen Problem diskutiert in der Post, ist es besser, nur die "Controller als" -Technik zu verwenden und sie auch auf die Methoden anzuwenden.


In diesem Kurs ( https://www.codeschool.com/courses/shaping-up-with-angular-js ) erklären sie, wie man "dieses" und viele andere Sachen benutzt.

Wenn Sie dem Controller über die Methode "this" eine Methode hinzufügen, müssen Sie diese in der Ansicht mit dem Controller-Namen "dot" Ihre Eigenschaft oder Methode aufrufen.

Wenn Sie beispielsweise Ihren Controller in der Ansicht verwenden, haben Sie möglicherweise folgenden Code:

    <div data-ng-controller="YourController as aliasOfYourController">

       Your first pane is {{aliasOfYourController.panes[0]}}

    </div>




this