'this' vs $ scope w kontrolerach AngularJS

W sekcji "Utwórz komponenty" na stronie głównej AngularJS znajduje się przykład:

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

Zwróć uwagę, jak Metoda select jest dodawana do $scope, ale metoda addPane jest dodawana do this. Jeśli zmienię go na $scope.addPane, Kod się zepsuje.

Dokumentacja mówi, że w rzeczywistości istnieje różnica, ale nie wspomina, jaka jest różnica:

Poprzednie wersje Angular (pre 1.0 RC) pozwoliły używać this zamiennie z Metoda $scope, ale tak już nie jest. Wewnątrz metod zdefiniowanych w zakresie this i $scope są wymienne (zestawy kątowe this do $scope), ale nie wewnątrz twojego konstruktora kontrolera.

Jak działa this i $scope w kontrolerach AngularJS?

Author: Peter Mortensen, 2012-07-23

7 answers

"Jak działają this i $scope w kontrolerach AngularJS?"

Krótka odpowiedź :

  • this
    • gdy wywoływana jest funkcja konstruktora kontrolera, this jest kontrolerem.
    • gdy wywołana jest funkcja zdefiniowana na obiekcie $scope, this jest "zakresem, w którym funkcja została wywołana". To może(lub nie!) be the $scope that the function is defined on. Zatem wewnątrz funkcji, this i $scope mogą Nie bądź taki sam.
  • $scope
    • każdy kontroler ma powiązany obiekt $scope.
    • funkcja kontrolera (konstruktora) jest odpowiedzialna za ustawienie właściwości modelu i funkcji/zachowania na powiązanym z nim $scope.
    • tylko metody zdefiniowane na tym obiekcie $scope (i nadrzędne obiekty scope, jeśli w grze jest dziedziczenie prototypowe) są dostępne z widoku HTML/. Np. z ng-click, filtrów itp.

Długie odpowiedź :

Funkcja kontrolera jest funkcją konstruktora JavaScript. Podczas wykonywania funkcji konstruktora (np. podczas ładowania widoku), this (tzn. "kontekst funkcji") jest ustawiany na obiekt kontrolera. Tak więc w funkcji konstruktora kontrolera "tabs", gdy zostanie utworzona funkcja addPane

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

Jest tworzony na obiekcie kontrolera, a nie na $scope. Widoki nie mogą zobaczyć funkcji addPane -- mają dostęp tylko do funkcji zdefiniowanych w $scope. Innymi słowy, w HTML to nie zadziała:

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

Po wykonaniu funkcji konstruktora kontrolera "tabs" mamy:

po tabs Controller Constructor funkcja

Przerywana czarna linia wskazuje dziedziczenie prototypowe-izolowany zakres prototypowo dziedziczy z Zakres . (Nie dziedziczy prototypowo z zakresu, w którym dyrektywa została napotkana w HTML.)

Teraz funkcja link dyrektywy pane chce komunikować się z dyrektywą tabs (co naprawdę oznacza, że musi w jakiś sposób wpłynąć na tabulatory isolate $scope). Zdarzenia mogą być użyte, ale innym mechanizmem jest posiadanie dyrektywy pane require kontrolera tabs. (Wydaje się, że nie istnieje mechanizm dla dyrektywy pane do require tabs $scope.)

Nasuwa się więc pytanie: jeśli mamy tylko dostęp do kontrolera tabs, to w jaki sposób uzyskamy dostęp do tabs isolate $scope (czego tak naprawdę chcemy)?

Czerwona kropkowana linia jest odpowiedzią. Na funkcja addPane ()" scope "(mam tu na myśli JavaScript ' s function scope/closures) daje funkcji dostęp do tabulatorów isolate $scope. To znaczy, addPane() ma dostęp do "tabs IsolateScope" na powyższym diagramie z powodu zamknięcia, które zostało utworzone podczas definiowania addPane (). (Gdybyśmy zamiast tego zdefiniowali addpane () w obiekcie tabs $scope, dyrektywa pane nie miałaby dostępu do tej funkcji, a zatem nie miałaby możliwości komunikowania się z tabs $scope.)

Aby odpowiedzieć druga część twojego pytania: how does $scope work in controllers?:

W funkcjach zdefiniowanych na $scope, this jest ustawione na "$scope w efekcie Gdzie / Kiedy funkcja została wywołana". Załóżmy, że mamy następujący kod 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>

I ParentCtrl (wyłącznie) ma

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

Kliknięcie pierwszego linku pokaże, że this i $scope są takie same, ponieważ "zakres obowiązujący, gdy funkcja została wywołana " jest zakresem skojarzonym z ParentCtrl.

Kliknięcie drugiego linku ujawni this i $scope, a nie tym samym, ponieważ "zakres obowiązujący, gdy funkcja została wywołana" jest zakresem związanym z ChildCtrl. Więc tutaj {[4] } jest ustawione na ChildCtrl ' s $scope. Wewnątrz metody, $scope jest nadal $scope ParentCtrl.

Fiddle

Staram się nie używać this wewnątrz funkcji zdefiniowanej na $scope, ponieważ staje się to mylące, na który $scope ma wpływ, zwłaszcza biorąc pod uwagę, że ng-repeat, ng-include, ng-switch i dyrektywy wszyscy mogą tworzyć własne lunety dla dzieci.

 1006
Author: Mark Rajcok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-01 10:32:30

Powodem przypisania do tego "addPane" jest dyrektywa <pane>.

Dyrektywa pane robi require: '^tabs', która umieszcza kontroler tabs z nadrzędnej dyrektywy, w funkcji link.

addPane jest przypisany do this tak, że funkcja link pane może go zobaczyć. Następnie w funkcji pane link, addPane jest tylko właściwością kontrolera tabs i jest to tylko tabsControllerObject.addPane. Tak więc funkcja łączenia dyrektywy pane może uzyskać dostęp do kontrolera tabulatorów obiekt i tym samym dostęp do metody addPane.

Mam nadzieję, że moje wyjaśnienie jest wystarczająco jasne.. trudno to wyjaśnić.
 56
Author: Andrew Joslin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-10 09:11:52

Właśnie przeczytałem dość ciekawe Wyjaśnienie na temat różnicy między nimi i rosnącą preferencją dołączania modeli do kontrolera i aliasów kontrolera, aby powiązać modele z widokiem. http://toddmotto.com/digging-into-angulars-controller-as-syntax / to artykuł.

Uwaga: oryginalny link nadal istnieje, ale zmiany w formatowaniu sprawiły, że trudno go odczytać. Łatwiej jest wyświetlić w oryginale .

Nie wspomina o tym, ale definiując dyrektywy, jeśli chcesz podzielić coś między wieloma dyrektywami i nie chcesz mieć Usługi (istnieją uzasadnione przypadki, w których usługi są kłopotliwe), Dołącz dane do kontrolera dyrektywy nadrzędnej.

Usługa $scope zapewnia wiele przydatnych rzeczy, $watch jest najbardziej oczywistą, ale jeśli wszystko, czego potrzebujesz, aby powiązać dane z widokiem, użycie zwykłego kontrolera i 'kontrolera as' w szablonie jest w porządku i prawdopodobnie preferowane.

 28
Author: Derek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-19 16:57:53

Polecam przeczytać poniższy post: AngularJS: "Controller as" czy "$ scope"?

Opisuje bardzo dobrze zalety używania " Controller as "do wystawiania zmiennych nad"$scope".

Wiem, że pytałeś konkretnie o metody, a nie zmienne, ale myślę, że lepiej trzymać się jednej techniki i być z nią spójnym.

Więc moim zdaniem, ze względu na problem zmiennych omówiony w poście, lepiej po prostu użyć " kontrolera jako" techniki, a także zastosować ją do metod.

 20
Author: Liran Brimer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 09:29:25

W tym kursie ( https://www.codeschool.com/courses/shaping-up-with-angular-js ) wyjaśniają, jak używać "tego" i wielu innych rzeczy.

Jeśli dodajesz metodę do kontrolera za pomocą metody "this", musisz ją wywołać w widoku z nazwą kontrolera" dot " swojej właściwości lub metody.

Na przykład używając kontrolera w widoku możesz mieć taki kod:

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

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

    </div>
 16
Author: Sandro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-24 07:29:37

Poprzednie wersje Angular (pre 1.0 RC) pozwoliły na użycie tego zamiennie z metodą $ scope, ale nie jest to już case. Wewnątrz metod zdefiniowanych w zakresie this oraz $scope znajdują się wymienne (angular ustawia to na $scope), ale nie inaczej wewnątrz konstruktora kontrolera.

Aby przywrócić to zachowanie (czy ktoś wie dlaczego zostało zmienione?) można dodać:

return angular.extend($scope, this);

Na końcu funkcji kontrolera (pod warunkiem, że $scope został wstrzyknięty do tej funkcji kontrolera).

To ma przyjemny efekt posiadania dostępu do zakresu nadrzędnego poprzez obiekt kontrolera, który można uzyskać w potomku za pomocą require: '^myParentDirective'

 3
Author: Kamil Szot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-20 08:46:34

$ scope ma inne 'this' niż kontroler 'this'.Tak więc, jeśli umieścisz konsolę.log (this) wewnątrz kontrolera daje obiekt (controller) i to.addPane () dodaje metodę addPane do obiektu kontrolera. Ale $scope ma inny zakres i wszystkie metody w jego zakresie muszą być dostępne przez $scope.methodName (). this.methodName() wewnątrz kontrolera oznacza dodanie methos wewnątrz obiektu kontrolera.$scope.functionName() jest w HTML i wewnątrz

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

Wklej ten kod w edytorze i otwórz konsolę, aby widzisz...

 <!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>
 1
Author: Aniket Jha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-07 09:06:17