it-swarm.com.de

'this' vs $ scope in AngularJS-Controllern

Im Bereich "Komponenten erstellen" 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, wie die select-Methode zu $scope hinzugefügt wird, die addPane-Methode jedoch zu this. Wenn ich es in $scope.addPane ändere, bricht der Code.

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

In früheren Versionen von Angular (vor 1.0 RC) konnten Sie this austauschbar mit der $scope-Methode verwenden. Dies ist jedoch nicht mehr der Fall. Innerhalb von Methoden, die im Gültigkeitsbereich this und $scope definiert sind, sind austauschbar (Winkelsätze this bis $scope), ansonsten jedoch nicht in Ihrem Controller-Konstruktor.

Wie funktionieren this und $scope in AngularJS-Controllern?

987
Alexei Boronine

"Wie funktionieren this und $scope in AngularJS-Controllern?"

Kurze Antwort:

Lange Antwort:

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

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

es wird für das Controller-Objekt erstellt, nicht für $ scope. Ansichten können die addPane-Funktion 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 Controller-Konstruktorfunktion "tabs" ausgeführt wurde, haben wir Folgendes:

after tabs controller constructor function

Die gestrichelte schwarze Linie zeigt die prototypische Vererbung an - ein Isolatumfang, der prototypisch von/- Scope erbt. (Es erbt nicht prototypisch den Gültigkeitsbereich, in dem die Direktive im HTML gefunden wurde.)

Nun möchte die Link-Funktion der Bereichs-Direktive mit der Tabs-Direktive kommunizieren (was wirklich bedeutet, dass sie die Tabulatoren beeinflussen muss, die $ scope auf irgendeine Weise isolieren). Ereignisse könnten verwendet werden, aber ein anderer Mechanismus besteht darin, dass die Bereichsanweisung require den Registerkarten-Controller hat. (Es scheint keinen Mechanismus für die Bereichsrichtlinie zu geben, mit der require die Registerkarten $ Gültigkeitsbereich sind.)

Das wirft also die Frage auf: Wenn wir nur Zugriff auf den Tabs-Controller haben, wie können wir dann auf die Tabs zugreifen, die $ scope (was ist das, was wir wirklich wollen) haben?

Nun, die rote gepunktete Linie ist die Antwort. Der Funktionsumfang der Funktion addPane () (ich beziehe mich hier auf die Funktionsumfang/Schließungen von JavaScript) gibt der Funktion Zugriff auf die Tabs isolate $ scope. Das heißt, addPane () hat Zugriff auf die "Registerkarten IsolateScope" im obigen Diagramm, da bei der Definition von addPane () ein Abschluss erstellt wurde. (Wenn wir stattdessen addPane () für das $ scope -Objekt der Tabs definiert hätten, hätte die pane Direktive keinen Zugriff auf diese Funktion, und daher hätte sie keine Möglichkeit, mit den $ tabs der Tabs zu kommunizieren.)

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

Innerhalb von Funktionen, die für $ scope definiert sind, ist this auf "den Gültigkeitsbereich von $ scope wo/wann die Funktion aufgerufen wurde" festgelegt. Nehmen wir an, wir haben folgendes HTML:

<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 (nur) hat

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

Wenn Sie auf den ersten Link klicken, wird angezeigt, dass this und $scope gleich sind, da "der Gültigkeitsbereich, in dem die Funktion aufgerufen wurde" der der ParentCtrl-Gültigkeitsbereich zugeordnete Bereich ist.

Wenn Sie auf den zweiten Link klicken, werden this und $scopenicht gleich, da "der Gültigkeitsbereich beim Aufruf der Funktion" der der ChildCtrl zugewiesene Gültigkeitsbereich ist. Hier ist also this auf ChildCtrls $scope gesetzt. Innerhalb der Methode ist $scope immer noch der $ -Bereich von ParentCtrl.

Fiddle

Ich versuche, this nicht innerhalb einer Funktion zu verwenden, die für $ scope definiert ist, da es verwirrend wird, welcher $ scope betroffen ist, vor allem wenn man bedenkt, dass ng-repeat, ng-include, ng-switch und Direktiven alle ihre eigenen untergeordneten Bereiche erstellen können .

971
Mark Rajcok

Der Grund für 'addPane' ist auf die <pane>-Direktive zurückzuführen.

Die pane-Direktive macht require: '^tabs', wodurch das Controller-Objekt der Registerkarten aus einer übergeordneten Direktive in die Link-Funktion eingefügt wird.

addPane ist this zugewiesen, damit die pane link-Funktion sie sehen kann. In der pane link-Funktion ist addPane nur eine Eigenschaft des tabs-Controllers und nur tabsControllerObject.addPane. Die Verknüpfungsfunktion der Bereichsanweisung kann also auf das Controller-Objekt der Registerkarten und somit auf die addPane-Methode zugreifen.

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

53
Andrew Joslin

Ich habe gerade eine ziemlich interessante Erklärung über den Unterschied zwischen den beiden gelesen und eine wachsende Vorliebe, Modelle an den Controller anzuschließen und den Controller als Alias ​​zu bezeichnen, um Modelle an die Ansicht zu binden. http://toddmotto.com/digging-into-angulars-controller-as-syntax/ ist der Artikel. Er erwähnt es nicht, aber wenn Sie Richtlinien definieren, müssen Sie die Daten an den Controller der übergeordneten Direktive anhängen, wenn Sie etwas für mehrere Anweisungen freigeben möchten und keinen Dienst wünschen (es gibt legitime Fälle, in denen Dienste unangenehm sind). Der $ scope-Dienst bietet viele nützliche Dinge, wobei $ watch das offensichtlichste ist. Wenn Sie jedoch nur Daten an die Ansicht binden müssen, ist die Verwendung des einfachen Controllers und des Controllers in der Vorlage in Ordnung und möglicherweise vorzuziehen.

26
Derek

Ich empfehle Ihnen, den folgenden Beitrag zu lesen: AngularJS: "Controller as" oder "$ scope"?

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

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. 

Meiner Meinung nach ist es wegen des in der Post diskutierten Variablenproblems besser, die "Controller as" -Technik zu verwenden und sie auch auf die Methoden anzuwenden.

18
Liran Brimer

In diesem Kurs ( https://www.codeschool.com/courses/shaping-up-with-angular-js ) wird erklärt, wie man "this" und viele andere Dinge verwendet.

Wenn Sie dem Controller über diese Methode eine Methode hinzufügen, müssen Sie diese in der Ansicht mit dem Namen des Controllers "dot" Ihrer 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>
15
Sandro

In früheren Versionen von Angular (vor 1.0 RC) konnten Sie diese .__ verwenden. austauschbar mit der $ scope-Methode, aber dies ist nicht mehr die Fall. Innerhalb der im Geltungsbereich definierten Methoden sind dies und $ austauschbar (Winkel setzt dies auf $ scope), aber sonst nicht in Ihrem Controller-Konstruktor.

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

return angular.extend($scope, this);

am Ende Ihrer Controller-Funktion (vorausgesetzt, dass $ scope in diese Controller-Funktion eingefügt wurde).

Dies hat eine gute Wirkung, wenn Sie über ein Controller-Objekt auf den übergeordneten Bereich zugreifen können, das Sie mit require: '^myParentDirective' in das untergeordnete Objekt aufnehmen können.

3
Kamil Szot

$ scope hat ein anderes 'this' als der Controller 'this'. Wenn Sie also eine console.log (this) in den Controller einfügen, erhalten Sie ein Objekt (Controller) und this.addPane () fügt dem Controller-Objekt die addPane-Methode hinzu. $ Scope hat jedoch einen anderen Gültigkeitsbereich, und alle Methoden in seinem Gültigkeitsbereich müssen über $ scope.methodName () .this.methodName() im Controller aufgerufen werden. Das bedeutet, Methos im Controller-Objekt hinzuzufügen .$scope.functionName() ist in HTML und inside 

$scope.functionName(){
    this.name="Name";
    //or
    $scope.myname="myname"//are same}

Fügen Sie diesen Code in Ihren Editor ein und öffnen Sie die Konsole.

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=Edge">
    <title>this $sope vs controller</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
    <script>
        var app=angular.module("myApp",[]);
app.controller("ctrlExample",function($scope){
          console.log("ctrl 'this'",this);
          //this(object) of controller different then $scope
          $scope.firstName="Andy";
          $scope.lastName="Bot";
          this.nickName="ABot";
          this.controllerMethod=function(){

            console.log("controllerMethod ",this);
          }
          $scope.show=function(){
              console.log("$scope 'this",this);
              //this of $scope
              $scope.message="Welcome User";
          }

        });
</script>
</head>
<body ng-app="myApp" >
<div ng-controller="ctrlExample">
       Comming From $SCOPE :{{firstName}}
       <br><br>
       Comming from $SCOPE:{{lastName}}
       <br><br>
       Should Come From Controller:{{nickName}}
       <p>
            Blank nickName is because nickName is attached to 
           'this' of controller.
       </p>

       <br><br>
       <button ng-click="controllerMethod()">Controller Method</button>

       <br><br>
       <button ng-click="show()">Show</button>
       <p>{{message}}</p>

   </div>

</body>
</html>
0
Aniket Jha