it-swarm.com.de

Wie verwende ich $ scope. $ Watch und $ scope. $ In AngularJS?

Ich verstehe nicht, wie man $scope.$watch und $scope.$apply benutzt. Die offizielle Dokumentation ist nicht hilfreich.

Was ich nicht genau verstehe:

  • Sind sie mit dem DOM verbunden?
  • Wie kann ich DOM-Änderungen am Modell aktualisieren?
  • Was ist der Verbindungspunkt zwischen ihnen?

Ich habe versucht dieses Tutorial , aber es setzt das Verständnis von $watch und $apply als selbstverständlich voraus.

Was tun $apply und $watch und wie verwende ich sie angemessen?

1066
ilyo

Sie müssen wissen, wie AngularJS funktioniert, um es zu verstehen.

Digest-Zyklus und $ scope

In erster Linie definiert AngularJS ein Konzept eines sogenannten Digest-Zyklus . Dieser Zyklus kann als Schleife betrachtet werden, in der AngularJS prüft, ob Änderungen an allen Variablen vorliegen, die von allen $scopes überwacht werden . Wenn Sie also $scope.myVar in Ihrem Controller definiert haben und diese Variable zum Überwachen markiert wurde , weisen Sie AngularJS implizit an, die Änderungen zu überwachen on myVar in jeder Iteration der Schleife.

Eine natürliche Folgefrage wäre: Ist alles damit verbunden, dass $scope beobachtet wird? Zum Glück nein. Wenn Sie auf Änderungen an jedem Objekt in Ihrem $scope achten würden, würde die Auswertung einer Digest-Schleife schnell Ewigkeiten dauern und Sie würden schnell auf Leistungsprobleme stoßen. Aus diesem Grund hat uns das AngularJS-Team zwei Möglichkeiten gegeben, eine $scope -Variable als überwacht zu deklarieren (siehe unten).

$ watch hilft dabei, auf $ scope-Änderungen zu achten

Es gibt zwei Möglichkeiten, eine $scope -Variable als überwacht zu deklarieren.

  1. Indem Sie es in Ihrer Vorlage über den Ausdruck <span>{{myVar}}</span> verwenden
  2. Durch manuelles Hinzufügen über den Dienst $watch

Anzeige 1) Dies ist das häufigste Szenario und ich bin sicher, dass Sie es bereits gesehen haben, aber Sie wussten nicht, dass dies eine Uhr im Hintergrund erstellt hat. Ja, das hatte es! Mit AngularJS-Anweisungen (wie ng-repeat) können auch implizite Überwachungen erstellt werden.

Ad 2) So erstellen Sie Ihre eigenen Uhren . Mit dem Dienst $watch können Sie Code ausführen, wenn sich ein Wert geändert hat, der an $scope angehängt ist. Es wird selten verwendet, ist aber manchmal hilfreich. Wenn Sie beispielsweise bei jeder Änderung von 'myVar' Code ausführen möchten, können Sie Folgendes tun:

function MyController($scope) {

    $scope.myVar = 1;

    $scope.$watch('myVar', function() {
        alert('hey, myVar has changed!');
    });

    $scope.buttonClicked = function() {
        $scope.myVar = 2; // This will trigger $watch expression to kick in
    };
}

Mit $ apply können Änderungen in den Digest-Zyklus integriert werden

Sie können sich die Funktion $apply als einen Integrationsmechanismus vorstellen . Sie sehen, jedes Mal, wenn Sie eine überwachte Variable ändern, die direkt an das Objekt $scope angehängt ist, weiß AngularJS, dass die Änderung stattgefunden hat. Dies liegt daran, dass AngularJS diese Änderungen bereits überwachen konnte. Wenn dies in Code geschieht, der vom Framework verwaltet wird, wird der Digest-Zyklus fortgesetzt.

Manchmal möchten Sie jedoch einen Wert außerhalb der AngularJS-Welt ändern und sehen, dass sich die Änderungen normal ausbreiten. Bedenken Sie Folgendes: Sie haben einen $scope.myVar -Wert, der im $.ajax() -Handler einer jQuery geändert wird. Dies wird irgendwann in Zukunft passieren. AngularJS kann das nicht abwarten, da es nicht angewiesen wurde, auf jQuery zu warten.

Um dies in Angriff zu nehmen, wurde $apply eingeführt. Hiermit können Sie den Aufschlusszyklus explizit starten. Sie sollten dies jedoch nur verwenden, um einige Daten nach AngularJS zu migrieren (Integration mit anderen Frameworks). Verwenden Sie diese Methode jedoch niemals in Kombination mit regulärem AngularJS-Code, da AngularJS dann einen Fehler auslöst.

Wie hängt das alles mit dem DOM zusammen?

Nun, du solltest dem Tutorial wirklich wieder folgen, jetzt wo du das alles weißt. Der Digest-Zyklus stellt sicher, dass die Benutzeroberfläche und der JavaScript-Code synchron bleiben, indem jeder an alle $scopes angehängte Beobachter ausgewertet wird, solange sich nichts ändert. Wenn in der Digest-Schleife keine Änderungen mehr vorgenommen werden, gilt dies als abgeschlossen.

Sie können Objekte an das Objekt $scope anhängen, entweder explizit im Controller oder indem Sie sie in der Form {{expression}} direkt in der Ansicht deklarieren.

Ich hoffe, das hilft, einige Grundkenntnisse über all dies zu klären.

Weitere Lesungen:

1717
ŁukaszBachman

In AngularJS aktualisieren wir unsere Modelle und unsere Ansichten/Vorlagen aktualisieren das DOM "automatisch" (über integrierte oder benutzerdefinierte Anweisungen).

$ apply und $ watch, beide Methoden von Scope, beziehen sich nicht auf das DOM.

Die Seite Concepts (Abschnitt "Runtime") enthält eine ziemlich gute Erklärung für die $ digest-Schleife, $ apply, die $ evalAsync-Warteschlange und die $ watch-Liste. Hier ist das Bild, das den Text begleitet:

$digest loop

Jeder Code, der Zugriff auf einen Bereich hat - normalerweise Controller und Direktiven (deren Verknüpfungsfunktionen und/oder deren Controller) - kann ein " watchExpression " einrichten, das AngularJS anhand dieses Bereichs auswertet. Diese Auswertung erfolgt immer dann, wenn AngularJS in seine $ digest-Schleife eintritt (insbesondere in die "$ watch list" -Schleife). Sie können einzelne Bereichseigenschaften überwachen, Sie können eine Funktion definieren, um zwei Eigenschaften gemeinsam zu überwachen, Sie können die Länge eines Arrays überwachen usw.

Wenn Dinge "innerhalb von AngularJS" passieren - Sie tippen z. B. in ein Textfeld, in dem AngularJS für bidirektionale Datenbindung aktiviert ist (dh ein ng-Modell verwendet), ein $ http-Rückruffeuer usw. -, wurde $ apply bereits aufgerufen befinden sich im "AngularJS" -Rechteck in der obigen Abbildung. Alle watchExpressions werden ausgewertet (möglicherweise mehrmals - bis keine weiteren Änderungen mehr festgestellt werden).

Wenn Dinge "außerhalb von AngularJS" passieren - Sie haben beispielsweise bind () in einer Direktive verwendet und dann wird dieses Ereignis ausgelöst, was dazu führt, dass Ihr Rückruf aufgerufen wird, oder dass ein von jQuery registrierter Rückruf ausgelöst wird - befinden wir uns immer noch im "nativen" Rechteck. Wenn der Rückrufcode irgendetwas ändert, das von $ watch beobachtet wird, rufen Sie $ apply auf, um in das AngularJS-Rechteck zu gelangen, wodurch die $ digest-Schleife ausgeführt wird, und AngularJS wird die Änderung bemerken und ihre Wirkung entfalten.

157
Mark Rajcok

Dieser Blog wurde alles behandelt, um Beispiele und verständliche Erklärungen zu erstellen.

Die AngularJS $scope -Funktionen $watch(), $digest() und $apply() sind einige der zentralen Funktionen in AngularJS. Das Verstehen von $watch(), $digest() und $apply() ist wichtig, um AngularJS zu verstehen.

Wenn Sie eine Datenbindung von einer beliebigen Stelle in Ihrer Ansicht zu einer Variablen im $ scope-Objekt erstellen, erstellt AngularJS intern eine "Überwachung". Eine Uhr bedeutet, dass AngularJS Änderungen in der Variablen auf dem $scope object überwacht. Das Framework "beobachtet" die Variable. Uhren werden mit der Funktion $scope.$watch() erstellt, auf die ich später in diesem Text eingehen werde.

An wichtigen Stellen Ihrer Anwendung ruft AngularJS die Funktion $scope.$digest() auf. Diese Funktion durchläuft alle Überwachungen und prüft, ob sich eine der überwachten Variablen geändert hat. Wenn sich eine überwachte Variable geändert hat, wird eine entsprechende Listener-Funktion aufgerufen. Die Listener-Funktion erledigt alle erforderlichen Aufgaben, z. B. das Ändern eines HTML-Texts, um den neuen Wert der überwachten Variablen widerzuspiegeln. Daher löst die Funktion $digest() die Aktualisierung der Datenbindung aus.

In den meisten Fällen ruft AngularJS die Funktionen $ scope. $ Watch () und $scope.$digest() für Sie auf, in manchen Situationen müssen Sie sie jedoch selbst aufrufen. Daher ist es sehr gut zu wissen, wie sie funktionieren.

Die Funktion $scope.$apply() wird verwendet, um einen Code auszuführen und anschließend $scope.$digest() aufzurufen, damit alle Uhren überprüft und die entsprechenden Funktionen des Watch Listener aufgerufen werden. Die Funktion $apply() ist nützlich, wenn AngularJS in anderen Code integriert wird.

Im weiteren Verlauf dieses Textes werde ich näher auf die Funktionen $watch(), $digest() und $apply() eingehen.

$ watch ()

Die Funktion $scope.watch() erstellt eine Überwachung einer Variablen. Wenn Sie eine Uhr registrieren, übergeben Sie der Funktion $watch() zwei Funktionen als Parameter:

  • Eine Wertfunktion
  • Eine Listener-Funktion

Hier ist ein Beispiel:

$scope.$watch(function() {},
              function() {}
             );

Die erste Funktion ist die Wertfunktion und die zweite Funktion ist die Listener-Funktion.

Die Wertfunktion sollte den Wert zurückgeben, der gerade überwacht wird. AngularJS kann dann den zurückgegebenen Wert mit dem Wert vergleichen, den die Überwachungsfunktion beim letzten Mal zurückgegeben hat. Auf diese Weise kann AngularJS feststellen, ob sich der Wert geändert hat. Hier ist ein Beispiel:

$scope.$watch(function(scope) { return scope.data.myVar },
              function() {}
             );

Diese Beispiel-Valule-Funktion gibt die Variable $scopescope.data.myVar zurück. Wenn sich der Wert dieser Variablen ändert, wird ein anderer Wert zurückgegeben und AngularJS ruft die Listener-Funktion auf.

Beachten Sie, wie die Wertfunktion den Gültigkeitsbereich als Parameter annimmt (ohne das $ im Namen). Über diesen Parameter kann die Wertefunktion auf den $scope und seine Variablen zugreifen. Die Wertefunktion kann stattdessen auch globale Variablen überwachen, wenn Sie dies benötigen. In den meisten Fällen wird jedoch eine $scope -Variable überwacht.

Die Listener-Funktion sollte alle erforderlichen Aktionen ausführen, wenn sich der Wert geändert hat. Möglicherweise müssen Sie den Inhalt einer anderen Variablen ändern oder den Inhalt eines HTML-Elements oder Ähnliches festlegen. Hier ist ein Beispiel:

$scope.$watch(function(scope) { return scope.data.myVar },
              function(newValue, oldValue) {
                  document.getElementById("").innerHTML =
                      "" + newValue + "";
              }
             );

In diesem Beispiel wird der innere HTML-Code eines HTML-Elements auf den neuen Wert der Variablen festgelegt, der in das b-Element eingebettet ist, wodurch der Wert fett dargestellt wird. Sie hätten dies natürlich auch mit dem Code {{ data.myVar } tun können, aber dies ist nur ein Beispiel dafür, was Sie in der Listener-Funktion tun können.

$ digest ()

Die Funktion $scope.$digest() durchläuft alle Überwachungen in $scope object und den untergeordneten Objekten $ scope (falls vorhanden). Wenn $digest() über die Uhren iteriert, wird die Wertefunktion für jede Uhr aufgerufen. Wenn sich der von der value-Funktion zurückgegebene Wert von dem Wert unterscheidet, den sie beim letzten Aufruf zurückgegeben hat, wird die Listener-Funktion für diese Uhr aufgerufen.

Die Funktion $digest() wird immer dann aufgerufen, wenn AngularJS dies für erforderlich hält. Zum Beispiel, nachdem ein Button-Click-Handler ausgeführt wurde oder nachdem ein AJAX -Aufruf zurückgegeben wurde (nachdem die Rückruffunktion done ()/fail () ausgeführt wurde).

In einigen Fällen kann es vorkommen, dass AngularJS die Funktion $digest() nicht für Sie aufruft. Sie werden dies normalerweise feststellen, indem Sie feststellen, dass die Datenbindungen die angezeigten Werte nicht aktualisieren. Rufen Sie in diesem Fall $scope.$digest() auf und es sollte funktionieren. Oder Sie können stattdessen $scope.$apply() verwenden, was ich im nächsten Abschnitt erläutern werde.

$ apply ()

Die Funktion $scope.$apply() übernimmt eine Funktion als Parameter, die ausgeführt wird, und danach wird $scope.$digest() intern aufgerufen. Auf diese Weise können Sie leichter sicherstellen, dass alle Uhren überprüft und somit alle Datenbindungen aktualisiert werden. Hier ist ein $apply() Beispiel:

$scope.$apply(function() {
    $scope.data.myVar = "Another value";
});

Die an die Funktion $apply() als Parameter übergebene Funktion ändert den Wert von $scope.data.myVar. Wenn die Funktion beendet wird, ruft AngularJS die Funktion $scope.$digest() auf, sodass alle Uhren auf Änderungen der beobachteten Werte überprüft werden.

Beispiel

Schauen Sie sich dieses Beispiel an, um zu veranschaulichen, wie $watch(), $digest() und $apply() funktionieren:

<div ng-controller="myController">
    {{data.time}}

    <br/>
    <button ng-click="updateTime()">update time - ng-click</button>
    <button id="updateTimeButton"  >update time</button>
</div>


<script>
    var module       = angular.module("myapp", []);
    var myController1 = module.controller("myController", function($scope) {

        $scope.data = { time : new Date() };

        $scope.updateTime = function() {
            $scope.data.time = new Date();
        }

        document.getElementById("updateTimeButton")
                .addEventListener('click', function() {
            console.log("update time clicked");
            $scope.data.time = new Date();
        });
    });
</script>

dieses Beispiel bindet die Variable $scope.data.time an eine Interpolationsanweisung, die den Variablenwert in die HTML-Seite einfügt. Diese Bindung erzeugt intern eine Uhr auf dem $scope.data.time variable.

Das Beispiel enthält auch zwei Schaltflächen. An die erste Schaltfläche ist ein Listener ng-click angehängt. Wenn diese Schaltfläche angeklickt wird, wird die Funktion $scope.updateTime() aufgerufen, und danach ruft AngularJS $scope.$digest() auf, damit die Datenbindungen aktualisiert werden.

Über die zweite Schaltfläche wird ein standardmäßiger JavaScript-Ereignis-Listener aus der Controller-Funktion heraus angehängt. Wenn Sie auf die zweite Schaltfläche klicken, wird diese Listener-Funktion ausgeführt. Wie Sie sehen, funktionieren die Listener-Funktionen für beide Schaltflächen fast genauso, aber wenn die Listener-Funktion der zweiten Schaltfläche aufgerufen wird, wird die Datenbindung nicht aktualisiert. Dies liegt daran, dass $scope.$digest() nicht aufgerufen wird, nachdem der Ereignis-Listener der zweiten Schaltfläche ausgeführt wurde. Wenn Sie also auf die zweite Schaltfläche klicken, wird die Uhrzeit in der Variablen $scope.data.time aktualisiert, die neue Uhrzeit wird jedoch nie angezeigt.

Um dies zu beheben, können wir einen $scope.$digest() -Aufruf in die letzte Zeile des Schaltflächenereignis-Listeners einfügen:

document.getElementById("updateTimeButton")
        .addEventListener('click', function() {
    console.log("update time clicked");
    $scope.data.time = new Date();
    $scope.$digest();
});

Anstatt $digest() in der Button Listener-Funktion aufzurufen, hätten Sie auch die $apply() -Funktion wie folgt verwenden können:

document.getElementById("updateTimeButton")
        .addEventListener('click', function() {
    $scope.$apply(function() {
        console.log("update time clicked");
        $scope.data.time = new Date();
    });
});

Beachten Sie, wie die Funktion $scope.$apply() im Listener für Schaltflächenereignisse aufgerufen wird und wie die Aktualisierung der Variablen $scope.data.time in der Funktion ausgeführt wird, die als Parameter an die Funktion $apply() übergeben wird. Wenn der Funktionsaufruf $apply() AngularJS-Aufrufe $digest() intern beendet, werden alle Datenbindungen aktualisiert.

64
Alex Jolig

AngularJS erweitert diese events-loop und erstellt so etwas wie AngularJS context.

$ watch ()

Jedes Mal, wenn Sie etwas in der Benutzeroberfläche binden, fügen Sie ein $watch in eine $watch-Liste ein.

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />

Hier haben wir $scope.user, der an die erste Eingabe gebunden ist, und wir haben $scope.pass, der an die zweite Eingabe gebunden ist. Dazu fügen wir zwei $watches zur $watch-Liste hinz.

Wenn unser template geladen ist, sucht der Compiler in der Verknüpfungsphase nach jeder Direktive und erstellt alle erforderlichen $watches.

AngularJS bietet $watch, $watchcollection und $watch(true). Unten finden Sie ein übersichtliches Diagramm, in dem alle drei aus Beobachter in der Tiefe erläutert werden.

Enter image description here

angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
  $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];

  $scope.$watch("users", function() {
    console.log("**** reference checkers $watch ****")
  });

  $scope.$watchCollection("users", function() {
    console.log("**** Collection  checkers $watchCollection ****")
  });

  $scope.$watch("users", function() {
    console.log("**** equality checkers with $watch(true) ****")
  }, true);

  $timeout(function(){
     console.log("Triggers All ")
     $scope.users = [];
     $scope.$digest();

     console.log("Triggers $watchCollection and $watch(true)")
     $scope.users.Push({ name: 'Thalaivar'});
     $scope.$digest();

     console.log("Triggers $watch(true)")
     $scope.users[0].name = 'Superstar';
     $scope.$digest();
  });
}

http://jsfiddle.net/2Lyn0Lkb/

$digest loop

Wenn der Browser ein Ereignis empfängt, das vom AngularJS-Kontext verwaltet werden kann, wird die $digest-Schleife ausgelöst. Diese Schleife besteht aus zwei kleineren Schleifen. Einer verarbeitet die Warteschlange $evalAsync und der andere verarbeitet den $watch list. Der $digest durchläuft die Liste der $watch, die wir haben

app.controller('MainCtrl', function() {
  $scope.name = "vinoth";

  $scope.changeFoo = function() {
      $scope.name = "Thalaivar";
  }
});

{{ name }}
<button ng-click="changeFoo()">Change the name</button>

Hier haben wir nur einen $watch, da ng-click keine Uhren erstellt.

Wir drücken den Knopf.

  1. Der Browser empfängt ein Ereignis, das in den AngularJS-Kontext eingeht
  2. Die $digest-Schleife wird ausgeführt und fragt jeden $ watch nach Änderungen.
  3. Da der $watch, der nach Änderungen in $ scope.name gesucht hat, eine Änderung meldet, wird eine weitere $digest-Schleife erzwungen.
  4. Die neue Schleife meldet nichts.
  5. Der Browser erhält das Steuerelement zurück und aktualisiert das DOM entsprechend dem neuen Wert von $ scope.name
  6. Das Wichtigste dabei ist, dass JEDES Ereignis, das in den AngularJS-Kontext eintritt, eine $digest-Schleife ausführt. Das bedeutet, dass die Schleife jedes Mal, wenn wir einen Buchstaben in eine Eingabe schreiben, jeden $watch auf dieser Seite überprüft.

$ apply ()

Wenn Sie beim Auslösen eines Ereignisses $apply aufrufen, durchläuft es den Winkelkontext. Wenn Sie es jedoch nicht aufrufen, wird es außerhalb des Ereignisses ausgeführt. So einfach ist das. $apply RUFT DIE $digest() -Schleife intern auf und durchläuft alle Überwachungen, um sicherzustellen, dass das DOM mit dem neu aktualisierten Wert aktualisiert wird.

Die Methode $apply() löst Beobachter für die gesamte Kette $scope aus, wohingegen die Methode $digest() nur Beobachter für den aktuellen $scope und dessen children auslöst. Wenn keines der übergeordneten $scope-Objekte die lokalen Änderungen kennen muss, können Sie $digest() verwenden.

45
Thalaivar

Es gibt auch $watchGroup und $watchCollection. Insbesondere ist $watchGroup sehr hilfreich, wenn Sie eine Funktion zum Aktualisieren eines Objekts mit mehreren Eigenschaften in einer Ansicht aufrufen möchten, die kein dom-Objekt ist, z. andere Ansicht in Canvas, WebGL oder Server Anfrage. Hier die Dokumentation Link .

17

Ich habe sehr ausführliche Videos gefunden, die $watch, $apply, $digest und Digest-Zyklen abdecken in:

Im Folgenden finden Sie einige Folien, die in diesen Videos verwendet werden, um die Konzepte zu erläutern (nur für den Fall, dass die obigen Links entfernt werden oder nicht funktionieren).

Enter image description here

In der obigen Abbildung wird "$ scope.c" nicht überwacht, da es in keiner der Datenbindungen (im Markup) verwendet wird. Die anderen beiden ($scope.a und $scope.b) werden angezeigt.

Enter image description here

Aus dem obigen Bild: AngularJS erfasst basierend auf dem jeweiligen Browser-Ereignis das Ereignis, führt einen Digest-Zyklus durch (durchläuft alle Überwachungen auf Änderungen), führt Überwachungsfunktionen aus und aktualisiert das DOM. Wenn keine Browser-Ereignisse vorliegen, kann der Digest-Zyklus manuell mit $apply oder $digest ausgelöst werden.

Mehr über $apply und $digest:

Enter image description here

17
user203687

Beenden Sie einfach das Lesen aller oben, langweilig und schläfrig (sorry, aber es ist wahr). Sehr technisch, gründlich, detailliert und trocken. Warum schreibe ich? Da AngularJS riesig ist, können viele miteinander verbundene Konzepte jeden verrückt machen. Ich habe mich oft gefragt, ob ich nicht schlau genug bin, sie zu verstehen. Nein! Es liegt daran, dass so wenige die Technik in einer für Dummiesprache ohne alle Terminologien erklären können! Okay, lass es mich versuchen:

1) Das sind alles ereignisgesteuerte Dinge. (Ich höre das Lachen, aber lies weiter)

Wenn Sie nicht wissen, was ereignisgesteuert ist, denken Sie, Sie platzieren eine Schaltfläche auf der Seite, schließen sie mit einer Funktion an, indem Sie auf "On-Click" klicken, und warten, bis Benutzer darauf klicken, um die Aktionen auszulösen, die Sie in die Seite einfügen Funktion. Oder denken Sie an "Trigger" von SQL Server/Oracle.

2) $ watch ist "on-click".

Das Besondere daran ist, dass es 2 Funktionen als Parameter verwendet, wobei die erste den Wert des Ereignisses angibt und die zweite den Wert berücksichtigt ...

) $ digest ist der Chef, der unermüdlich herumschaut, bla-bla-bla, aber ein guter Chef.

4) $ apply gibt Ihnen die Möglichkeit, dies manuell zu tun., wie ein Fail-Proof (falls das Klicken nicht eintritt, müssen Sie es ausführen.)

Machen wir es uns jetzt anschaulich. Stellen Sie sich das vor, um die Idee noch einfacher zu fassen:

In einem Restaurant

- WAITERS sollen Bestellungen von Kunden entgegennehmen, das ist

$watch(
  function(){return orders;},
  function(){Kitchen make it;}
);

- MANAGER rennt herum, um sicherzustellen, dass alle Kellner wach sind und auf Anzeichen von Kundenveränderungen reagieren. Dies ist $digest()

- Der EIGENTÜMER hat die ultimative Kraft, alle auf Anfrage anzutreiben. Dies ist $apply()

12
Jeb50