force - Come posso usare $ scope. $ Watch e $ scope. $ Applicare in AngularJS?




this angular js (5)

È necessario essere consapevoli di come funziona AngularJS per comprenderlo.

Ciclo di digest e $ scope

Innanzi tutto, AngularJS definisce un concetto di un cosiddetto ciclo di digestione . Questo ciclo può essere considerato come un ciclo, durante il quale AngularJS controlla se ci sono delle modifiche a tutte le variabili controllate da tutti gli $scope . Quindi, se hai $scope.myVar definito nel controller e questa variabile è stata contrassegnata per essere guardata , allora stai implicitamente dicendo ad AngularJS di monitorare le modifiche su myVar in ogni iterazione del ciclo.

Una domanda di follow-up naturale sarebbe: tutto ciò che è allegato a $scope viene guardato? Fortunatamente no. Se si desidera controllare le modifiche apportate a ogni oggetto in $scope , quindi rapidamente un ciclo di digest richiederà tempi di valutazione e si verificheranno rapidamente problemi di prestazioni. Questo è il motivo per cui il team di AngularJS ci ha offerto due modi per dichiarare una variabile $scope come vista (leggi sotto).

$ watch aiuta ad ascoltare i cambiamenti di $ scope

Esistono due modi per dichiarare una variabile $scope come guardata.

  1. <span>{{myVar}}</span> nel modello tramite l'espressione <span>{{myVar}}</span>
  2. Aggiungendolo manualmente tramite il servizio $watch

Annuncio 1) Questo è lo scenario più comune e sono sicuro che l'hai già visto prima, ma non sapevi che questo ha creato un orologio in background. Sì, aveva! Le direttive AngularJS (come ng-repeat ) possono anche creare orologi impliciti.

Annuncio 2) Ecco come si creano i propri orologi . $watch servizio $watch ti aiuta ad eseguire del codice quando è cambiato qualche valore collegato a $scope . È usato raramente, ma a volte è utile. Ad esempio, se vuoi eseguire un codice ogni volta che cambia "myVar", puoi fare quanto segue:

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

$ apply consente di integrare le modifiche con il ciclo di digest

Puoi pensare alla funzione $apply come a un meccanismo di integrazione . Vedete, ogni volta che si modifica direttamente una variabile controllata collegata all'oggetto $scope , AngularJS saprà che la modifica è avvenuta. Questo perché AngularJS sapeva già di monitorare tali cambiamenti. Quindi se succede nel codice gestito dal framework, il ciclo digest continuerà.

Tuttavia, a volte si desidera modificare un valore al di fuori del mondo AngularJS e vedere le modifiche propagarsi normalmente. Considera questo: hai un valore $scope.myVar che verrà modificato all'interno del $.ajax() jQuery. Questo accadrà a un certo punto in futuro. AngularJS non può aspettare che questo accada, dal momento che non è stato richiesto di aspettare su jQuery.

Per affrontare questo, è stata introdotta l' $apply . Ti consente di avviare il ciclo di digestione in modo esplicito. Tuttavia, dovresti utilizzarlo solo per migrare alcuni dati su AngularJS (integrazione con altri framework), ma non usare mai questo metodo combinato con il normale codice AngularJS, dato che AngularJS genererà quindi un errore.

Com'è collegato tutto questo al DOM?

Bene, dovresti davvero seguire di nuovo il tutorial, ora che sai tutto questo. Il ciclo di digest farà in modo che l'interfaccia utente e il codice JavaScript rimangano sincronizzati, valutando ogni watcher collegato a tutti $scope se non cambia nulla. Se non ci sono più cambiamenti nel ciclo digest, allora è considerato finito.

È possibile allegare oggetti all'oggetto $scope modo esplicito nel Controller o dichiarandoli in forma {{expression}} direttamente nella vista.

Spero che questo aiuti a chiarire alcune conoscenze di base su tutto questo.

Ulteriori letture:

Non capisco come usare $scope.$watch e $scope.$apply . La documentazione ufficiale non è utile.

Quello che non capisco in particolare:

  • Sono collegati al DOM?
  • Come posso aggiornare le modifiche del DOM al modello?
  • Qual è il punto di connessione tra loro?

Ho provato questo tutorial , ma ci vuole la comprensione di $watch e $apply for given.

Cosa fanno $apply e $watch do e come li uso in modo appropriato?


AngularJS estende questo ciclo di eventi , creando qualcosa chiamato AngularJS context .

$ watch ()

Ogni volta che leghi qualcosa nell'interfaccia utente, inserisci un $watch in una lista di $watch .

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

Qui abbiamo $scope.user , che è legato al primo input, e abbiamo $scope.pass , che è associato al secondo. Facendo questo aggiungiamo due $watch alla $watch list .

Quando il nostro modello è caricato, AKA nella fase di collegamento, il compilatore cercherà ogni direttiva e creerà tutti gli $watch necessari.

AngularJS fornisce $watch , $watchcollection e $watch(true) . Di seguito uno schema accurato che spiega in dettaglio tutti e tre gli osservatori .

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 ciclo di $digest

Quando il browser riceve un evento che può essere gestito dal contesto AngularJS, verrà generato il ciclo $digest . Questo ciclo è composto da due anelli più piccoli. Uno elabora la coda $evalAsync e l'altro elabora l' $watch list . $digest passerà in rassegna l'elenco di $watch che abbiamo

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

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

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

Qui abbiamo solo un $watch perché ng-click non crea orologi.

Premiamo il pulsante.

  1. Il browser riceve un evento che entrerà nel contesto di AngularJS
  2. Il ciclo $digest verrà eseguito e chiederà ad ogni $ watch di apportare modifiche.
  3. Poiché il $watch che stava osservando le modifiche in $ scope.name riporta una modifica, imporrà un altro ciclo $digest .
  4. Il nuovo ciclo non riporta nulla.
  5. Il browser riavvia il controllo e aggiornerà il DOM riflettendo il nuovo valore di $ scope.name
  6. La cosa importante qui è che OGNI evento che entra nel contesto di AngularJS eseguirà un ciclo $digest . Ciò significa che ogni volta che scriviamo una lettera in un input, il ciclo verrà eseguito controllando ogni $watch in questa pagina.

$ Applicare ()

Se chiami $apply quando un evento viene attivato, passerà attraverso il contesto angolare, ma se non lo chiami, verrà eseguito al di fuori di esso. È così facile. $apply chiamerà internamente il ciclo $digest() e itererà su tutti gli orologi per assicurare che il DOM sia aggiornato con il valore appena aggiornato.

Il metodo $apply() attiverà i watcher sull'intera catena $scope mentre il metodo $digest() attiverà solo i watcher sull'attuale $scope e sui suoi children . Quando nessuno degli oggetti $scope deve conoscere le modifiche locali, è possibile utilizzare $digest() .


Ci sono anche $watchGroup e $watchCollection . In particolare, $watchGroup è davvero utile se si desidera chiamare una funzione per aggiornare un oggetto che ha più proprietà in una vista che non è oggetto dom, ad esempio per altre viste in canvas, webGL o richieste server. Qui, il link alla documentazione.


Ho trovato video molto approfonditi che coprono i cicli $watch , $apply , $digest e digest in:

Di seguito sono riportate un paio di diapositive utilizzate in quei video per spiegare i concetti (nel caso in cui i collegamenti sopra riportati vengano rimossi / non funzionanti).

Nell'immagine sopra, "$ scope.c" non viene visto poiché non viene utilizzato in nessuno dei collegamenti dati (nel markup). Gli altri due ( $scope.a e $scope.b ) saranno guardati.

Dall'immagine sopra: In base al rispettivo evento del browser, AngularJS acquisisce l'evento, esegue il ciclo di digest (passa attraverso tutti gli orologi per le modifiche), esegue le funzioni di orologio e aggiorna il DOM. Se non sono eventi del browser, il ciclo di digest può essere attivato manualmente utilizzando $apply o $digest .

Ulteriori informazioni su $apply e $digest :


Questo blog è stato coperto da tutto ciò che crea esempi e spiegazioni comprensibili.

Le funzioni del $scope AngularJS $scope $watch(), $digest() e $apply() sono alcune delle funzioni centrali di AngularJS. Comprendere $watch() , $digest() e $apply() è essenziale per capire AngularJS.

Quando si crea un'associazione dati da qualche parte della vista a una variabile sull'oggetto $ scope, AngularJS crea internamente un "orologio". Un orologio significa che AngularJS guarda le modifiche nella variabile $scope object . La struttura sta "guardando" la variabile. Gli orologi vengono creati usando la funzione $scope.$watch() che tratterò più avanti in questo testo.

Nei punti chiave dell'applicazione AngularJS chiama la funzione $scope.$digest() . Questa funzione esegue iterazioni su tutti gli orologi e verifica se una delle variabili controllate è cambiata. Se una variabile controllata è cambiata, viene chiamata una funzione listener corrispondente. La funzione listener fa tutto il lavoro necessario, ad esempio modificando un testo HTML per riflettere il nuovo valore della variabile guardata. Pertanto, la funzione $digest() è ciò che attiva l'associazione dati per l'aggiornamento.

Il più delle volte AngularJS chiamerà $ scope. $ Watch () e $scope.$digest() per te, ma in alcune situazioni potresti dover chiamarli tu stesso. Quindi è davvero bello sapere come funzionano.

La funzione $scope.$apply() viene utilizzata per eseguire del codice, quindi chiamare $scope.$digest() , quindi tutti gli orologi vengono controllati e vengono chiamate le corrispondenti funzioni di watch watch. La funzione $apply() è utile quando si integra AngularJS con un altro codice.

Vedremo più in dettaglio le funzioni $watch(), $digest() e $apply() nella parte restante di questo testo.

$ Watch ()

La funzione $scope.watch() crea un orologio di alcune variabili. Quando registri un orologio, passi due funzioni come parametri alla funzione $watch() :

  • Una funzione di valore
  • Una funzione di ascolto

Ecco un esempio:

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

La prima funzione è la funzione valore e la seconda funzione è la funzione listener.

La funzione valore dovrebbe restituire il valore che si sta guardando. AngularJS può quindi controllare il valore restituito rispetto al valore restituito dall'ultima funzione dell'orologio. In questo modo AngularJS può determinare se il valore è cambiato. Ecco un esempio:

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

Questa funzione valule di esempio restituisce la variabile $scope scope.data.myVar . Se il valore di questa variabile cambia, verrà restituito un valore diverso e AngularJS chiamerà la funzione listener.

Si noti come la funzione value assuma l'ambito come parametro (senza $ nel nome). Tramite questo parametro, la funzione value può accedere a $scope e alle sue variabili. La funzione valore può anche controllare le variabili globali, se necessario, ma molto spesso si guarderà una variabile $scope .

La funzione listener dovrebbe fare tutto ciò che deve fare se il valore è cambiato. Forse è necessario modificare il contenuto di un'altra variabile o impostare il contenuto di un elemento HTML o qualcosa del genere. Ecco un esempio:

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

Questo esempio imposta l'HTML interno di un elemento HTML sul nuovo valore della variabile, incorporato nell'elemento b che rende il valore grassetto. Ovviamente avresti potuto farlo usando il codice {{ data.myVar } , ma questo è solo un esempio di cosa puoi fare all'interno della funzione listener.

$ Digest ()

La funzione $scope.$digest() esegue iterazioni su tutti gli orologi $scope object e sui suoi oggetti child $ scope (se ne ha). Quando $digest() esegue iterazioni sugli orologi, chiama la funzione valore per ciascun orologio. Se il valore restituito dalla funzione value è diverso dal valore restituito l'ultima volta che è stato chiamato, viene chiamata la funzione listener per quell'orologio.

La funzione $digest() viene chiamata ogni volta che AngularJS pensa che sia necessario. Ad esempio, dopo che un gestore di clic del pulsante è stato eseguito, o dopo che una chiamata AJAX tornata (dopo che la funzione di callback done () / fail () è stata eseguita).

Potresti imbatterti in alcuni casi in cui AngularJS non chiama la funzione $digest() per te. Di solito lo rilevi notando che le associazioni di dati non aggiornano i valori visualizzati. In tal caso, chiama $scope.$digest() e dovrebbe funzionare. Oppure, puoi forse usare $scope.$apply() invece che spiegherò nella prossima sezione.

$ Applicare ()

La funzione $scope.$apply() accetta una funzione come parametro che viene eseguita, e dopo tale $scope.$digest() viene chiamato internamente. In questo modo è più semplice accertarsi che tutti gli orologi siano stati controllati, quindi tutti i binding dei dati sono stati aggiornati. Ecco un esempio $apply() :

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

La funzione passata alla funzione $apply() come parametro cambierà il valore di $scope.data.myVar . Quando la funzione termina, AngularJS chiamerà la funzione $scope.$digest() modo che tutti gli orologi siano controllati per le modifiche nei valori osservati.

Esempio

Per illustrare come funzionano $watch() , $digest( ) e $apply() , guarda questo esempio:

<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>

il suo esempio lega la variabile $scope.data.time a una direttiva di interpolazione che unisce il valore della variabile alla pagina HTML. Questa associazione crea un orologio internamente sulla $scope.data.time variable .

L'esempio contiene anche due pulsanti. Il primo pulsante ha un ascoltatore ng-click collegato ad esso. Quando viene cliccato quel pulsante, viene chiamata la funzione $scope.updateTime() , e dopo che AngularJS chiama $scope.$digest() modo che i binding di dati vengano aggiornati.

Il secondo pulsante riceve un listener di eventi JavaScript standard collegato all'interno della funzione del controller. Quando viene fatto clic sul secondo pulsante, viene eseguita la funzione listener. Come potete vedere, le funzioni listener per entrambi i pulsanti hanno quasi lo stesso effetto, ma quando viene chiamata la funzione listener del secondo pulsante, l'associazione dati non viene aggiornata. Questo perché $scope.$digest() non viene chiamato dopo l'esecuzione del listener di eventi del secondo pulsante. Pertanto, se si fa clic sul secondo pulsante, l'ora viene aggiornata nella variabile $scope.data.time , ma la nuova ora non viene mai visualizzata.

Per risolvere il problema possiamo aggiungere una chiamata $scope.$digest() all'ultima riga del listener di eventi del pulsante, in questo modo:

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

Invece di chiamare $digest() all'interno della funzione listener dei pulsanti potresti anche aver usato la funzione $apply() questo modo:

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

Si noti come viene chiamata la funzione $scope.$apply() dall'interno del listener di eventi del pulsante e come l'aggiornamento della variabile $scope.data.time viene eseguito all'interno della funzione passata come parametro alla funzione $apply() . Quando la chiamata alla funzione $apply() termina AngularJS chiama $digest() internamente, quindi tutte le associazioni di dati vengono aggiornate.





angularjs-scope