javascript $watch - Funzionando con $ scope.$ Emit e $ scope.$ On




$scope new (12)

È necessario utilizzare $ rootScope per inviare e acquisire eventi tra i controller nella stessa app. Iniettare la dipendenza $ rootScope dai controller. Ecco un esempio funzionante.

app.controller('firstCtrl', function($scope, $rootScope) {        
        function firstCtrl($scope) {
        {
            $rootScope.$emit('someEvent', [1,2,3]);
        }
}

app.controller('secondCtrl', function($scope, $rootScope) {
        function secondCtrl($scope)
        {
            $rootScope.$on('someEvent', function(event, data) { console.log(data); });
        }
}

Gli eventi collegati all'oggetto $ scope funzionano solo nel controller proprietario. La comunicazione tra i controller avviene tramite $ rootScope o Servizi.

Come posso inviare il mio oggetto $scope da un controller a un altro usando .$emit e .$on metodi?

function firstCtrl($scope) {
    $scope.$emit('someEvent', [1,2,3]);
}

function secondCtrl($scope) {
    $scope.$on('someEvent', function(mass) { console.log(mass); });
}

Non funziona nel modo in cui penso che dovrebbe. Come funzionano $emit e $on ?


Per inviare $scope object da un controller a un altro, $rootScope.$broadcast e $rootScope.$emit qui come sono più utilizzati.

Caso 1 :

$ RootScope $ trasmissione:. -

$rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name

$rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event

$rootScope listener di $rootScope non viene distrutto automaticamente. Devi distruggerlo usando $destroy . È preferibile usare $scope.$on mentre gli ascoltatori su $scope vengono distrutti automaticamente, cioè non appena $ scope viene distrutto.

$scope.$on('myEvent', function(event, data) {}

O,

  var customeEventListener = $rootScope.$on('myEvent', function(event, data) {

  }
  $scope.$on('$destroy', function() {
        customeEventListener();
  });

Caso 2:

. $ RootScope $ emettono:

   $rootScope.$emit('myEvent',$scope.data);

   $rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works

La principale differenza tra $ emit e $ broadcast è che $ rootScope. $ Emette l'evento deve essere ascoltato usando $ rootScope. $ On, perché l'evento emesso non arriva mai attraverso la struttura ad albero. .
Anche in questo caso devi distruggere l'ascoltatore come nel caso di $ broadcast.

Modificare:

Preferisco non usare $rootScope.$broadcast + $scope.$on ma uso $rootScope.$emit+ $rootScope.$on . $rootScope.$broadcast + $scope.$on combo può causare seri problemi di prestazioni. Questo perché l'evento esploderà attraverso tutti gli ambiti.

Modifica 2 :

Il problema affrontato in questa risposta è stato risolto in angular.js versione 1.2.7. $ broadcast ora evita il bubbling sugli ambiti non registrati e viene eseguito con la stessa rapidità di $ emit.


Secondo i documenti di evento angularjs, la fine di ricezione dovrebbe contenere argomenti con una struttura simile

@params

- L'evento {Object} è l'oggetto evento che contiene informazioni sull'evento

- Argomenti {Object} che vengono passati dal callee (si noti che questo può essere solo uno così meglio da inviare sempre in un oggetto dizionario)

$scope.$on('fooEvent', function (event, args) { console.log(args) }); Dal tuo codice

Inoltre, se stai cercando di ottenere informazioni condivise su diversi controller, c'è un altro modo per ottenerlo e questi sono servizi angolari. Dal momento che i servizi sono singleton, le informazioni possono essere memorizzate e scaricate tra i controller. setter funziona in quel servizio, espone queste funzioni, crea variabili globali nel servizio e le usa per memorizzare le informazioni


Come posso inviare il mio oggetto $ scope da un controller a un altro usando $ emit e $ su metodi?

Puoi inviare qualsiasi oggetto desiderato nella gerarchia della tua app, incluso $ scope .

Ecco una rapida idea di come funzionano broadcast ed emit .

Notare i nodi sottostanti; tutto annidato nel nodo 3. Si utilizza broadcast ed emit quando si dispone di questo scenario.

Nota: il numero di ciascun nodo in questo esempio è arbitrario; potrebbe facilmente essere il numero uno; il numero due; o anche il numero 1,348. Ogni numero è solo un identificatore per questo esempio. Il punto di questo esempio è mostrare l'annidamento di controllori / direttive angolari.

                 3
           ------------
           |          |
         -----     ------
         1   |     2    |
      ---   ---   ---  ---
      | |   | |   | |  | |

Dai un'occhiata a questo albero. Come rispondi alle seguenti domande?

Nota: ci sono altri modi per rispondere a queste domande, ma qui discuteremo di trasmissione ed emettere . Inoltre, quando si legge sotto il testo si assume che ogni numero abbia il proprio file (direttiva, controller) ex one.js, two.js, three.js.

In che modo il nodo 1 parla al nodo 3 ?

Nel file one.js

scope.$emit('messageOne', someValue(s));

Nel file three.js - il nodo più in alto a tutti i nodi figli necessari per comunicare.

scope.$on('messageOne', someValue(s));

In che modo il nodo 2 parla al nodo 3?

Nel file two.js

scope.$emit('messageTwo', someValue(s));

Nel file three.js - il nodo più in alto a tutti i nodi figli necessari per comunicare.

scope.$on('messageTwo', someValue(s));

In che modo il nodo 3 parla al nodo 1 e / o al nodo 2?

Nel file three.js - il nodo più in alto a tutti i nodi figli necessari per comunicare.

scope.$broadcast('messageThree', someValue(s));

Nel file one.js && two.js qualunque sia il file che si desidera catturare il messaggio o entrambi.

scope.$on('messageThree', someValue(s));

In che modo il nodo 2 parla al nodo 1?

Nel file two.js

scope.$emit('messageTwo', someValue(s));

Nel file three.js - il nodo più in alto a tutti i nodi figli necessari per comunicare.

scope.$on('messageTwo', function( event, data ){
  scope.$broadcast( 'messageTwo', data );
});

Nel file one.js

scope.$on('messageTwo', someValue(s));

PERÒ

Quando tutti questi nodi figli annidati cercano di comunicare in questo modo, vedrai rapidamente molti $ on , $ broadcast e $ emit .

Ecco cosa mi piace fare.

Nel PARENT NODE più in alto ( 3 in questo caso ...), che potrebbe essere il controller genitore ...

Quindi, nel file three.js

scope.$on('pushChangesToAllNodes', function( event, message ){
  scope.$broadcast( message.name, message.data );
});

Ora in uno qualsiasi dei nodi figlio è necessario solo $ emettere il messaggio o catturarlo usando $ on .

NOTA: Normalmente è abbastanza facile parlare in un percorso annidato senza usare $ emit , $ broadcast o $ on , il che significa che la maggior parte dei casi d'uso si riferiscono a quando si tenta di ottenere il nodo 1 per comunicare con il nodo 2 o viceversa.

In che modo il nodo 2 parla al nodo 1?

Nel file two.js

scope.$emit('pushChangesToAllNodes', sendNewChanges());

function sendNewChanges(){ // for some event.
  return { name: 'talkToOne', data: [1,2,3] };
}

Nel file three.js - il nodo più in alto a tutti i nodi figli necessari per comunicare.

Abbiamo già gestito questo ricordo?

Nel file one.js

scope.$on('talkToOne', function( event, arrayOfNumbers ){
  arrayOfNumbers.forEach(function(number){
    console.log(number);
  });
});

Avrai comunque bisogno di usare $ on con ogni valore specifico che vuoi catturare, ma ora puoi creare qualsiasi cosa tu voglia in uno qualsiasi dei nodi senza doversi preoccupare di come ottenere il messaggio attraverso il gap del nodo genitore mentre catturiamo e trasmettiamo il generico pushChangesToAllNodes .

Spero che questo ti aiuti...


Ho finito per aggiungere una libreria EventEmitter esterna per proiettare come servizio e iniettarla ovunque mi servisse. Così posso "emettere" e "on" qualsiasi cosa senza curare l'ereditarietà dell'ambito. È meno problemi in questo modo e sicuramente prestazioni migliori. Anche più leggibile per me.

Supporto con caratteri jolly: EventEmitter2

Buona prestazione: eventemitter3

Altra alternativa: Drip


Vorrei inoltre suggerire una quarta opzione come alternativa migliore alle opzioni proposte da @zbynour.

Usa $rootScope.$emit piuttosto che $rootScope.$broadcast indipendentemente dalla relazione tra il controller trasmittente e quello ricevente. In questo modo, l'evento rimane all'interno del set di $rootScope.$$listeners mentre con $rootScope.$broadcast l'evento si propaga a tutti gli ambiti figli, la maggior parte dei quali probabilmente non saranno ascoltatori di quell'evento comunque. E naturalmente nel controller di ricezione si usa solo $rootScope.$on .

Per questa opzione è necessario ricordare di distruggere i listener di rootScope del controller:

var unbindEventHandler = $rootScope.$on('myEvent', myHandler);
$scope.$on('$destroy', function () {
  unbindEventHandler();
});

È possibile chiamare un servizio dal controller che restituisce una promessa e quindi utilizzarla nel controller. E usa ulteriormente $emit o $broadcast per informare gli altri controller su di esso. Nel mio caso, ho dovuto effettuare chiamate http tramite il mio servizio, quindi ho fatto qualcosa del genere:

function ParentController($scope, testService) {
    testService.getList()
        .then(function(data) {
            $scope.list = testService.list;
        })
        .finally(function() {
            $scope.$emit('listFetched');
        })


    function ChildController($scope, testService) {
        $scope.$on('listFetched', function(event, data) {
            // use the data accordingly
        })
    }

e il mio servizio è simile a questo

    app.service('testService', ['$http', function($http) {

        this.list = [];

        this.getList = function() {
            return $http.get(someUrl)
                .then(function(response) {
                    if (typeof response.data === 'object') {
                        list = response.data.results;

                        return response.data;
                    } else {
                        // invalid response
                        return $q.reject(response.data);
                    }

                }, function(response) {
                    // something went wrong
                    return $q.reject(response.data);
                });

        }

    }])

<!DOCTYPE html>
<html>

<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var app = angular.module('MyApp',[]);
app.controller('parentCtrl',function($scope){
  $scope.$on('MyEvent',function(event,data){    
    $scope.myData = data;
  });
 });

app.controller('childCtrl',function($scope){
  $scope.fireEvent = function(){ 
  $scope.$emit('MyEvent','Any Data');
  }  
 });
</script>
</head>
<body ng-app="MyApp">
<div ng-controller="parentCtrl" ng-model="myName">

{{myData}}

 <div ng-controller="childCtrl">
   <button ng-click="fireEvent()">Fire Event</button>
 </div>

</div>
</body>
</html>

Innanzitutto, la relazione sull'ambito genitore-figlio è importante. Hai due possibilità di emettere qualche evento:

  • $broadcast - invia l'evento in basso a tutti gli ambiti figlio,
  • $emit : invia l'evento verso l'alto attraverso la gerarchia dell'ambito.

Non so nulla sulla relazione dei tuoi controllori (scope), ma ci sono diverse opzioni:

  1. Se l'ambito di firstCtrl è padre dell'ambito secondCtrl , il tuo codice dovrebbe funzionare sostituendo $emit da $broadcast in firstCtrl :

    function firstCtrl($scope)
    {
        $scope.$broadcast('someEvent', [1,2,3]);
    }
    
    function secondCtrl($scope)
    {
        $scope.$on('someEvent', function(event, mass) { console.log(mass); });
    }
    
  2. Nel caso in cui non ci sia una relazione genitore-figlio tra i propri ambiti è possibile iniettare $rootScope nel controller e trasmettere l'evento a tutti gli ambiti figlio (cioè anche secondCtrl ).

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
    
  3. Infine, quando è necessario inviare l'evento dal controller secondario agli ambiti verso l'alto, è possibile utilizzare $scope.$emit . Se l'ambito di firstCtrl è padre dell'ambito secondCtrl :

    function firstCtrl($scope)
    {
        $scope.$on('someEvent', function(event, data) { console.log(data); });
    }
    
    function secondCtrl($scope)
    {
        $scope.$emit('someEvent', [1,2,3]);
    }
    

Questa è la mia funzione:

$rootScope.$emit('setTitle', newVal.full_name);

$rootScope.$on('setTitle', function(event, title) {
    if (scope.item) 
        scope.item.name = title;
    else 
        scope.item = {name: title};
});

Sotto codice mostra i due sub-controller da cui gli eventi vengono inviati verso l'alto al controller principale (rootScope)

<body ng-app="App">

    <div ng-controller="parentCtrl">

        <p>City : {{city}} </p>
        <p> Address : {{address}} </p>

        <div ng-controller="subCtrlOne">
            <input type="text" ng-model="city" />
            <button ng-click="getCity(city)">City !!!</button>
        </div>

        <div ng-controller="subCtrlTwo">

            <input type="text" ng-model="address" />
            <button ng-click="getAddrress(address)">Address !!!</button>

        </div>

    </div>

</body>

var App = angular.module('App', []);

// parent controller
App.controller('parentCtrl', parentCtrl);

parentCtrl.$inject = ["$scope"];

function parentCtrl($scope) {

    $scope.$on('cityBoom', function(events, data) {
        $scope.city = data;
    });

    $scope.$on('addrBoom', function(events, data) {
        $scope.address = data;
    });
}

// sub controller one

App.controller('subCtrlOne', subCtrlOne);

subCtrlOne.$inject = ['$scope'];

function subCtrlOne($scope) {

    $scope.getCity = function(city) {

        $scope.$emit('cityBoom', city);    
    }
}

// sub controller two

App.controller('subCtrlTwo', subCtrlTwo);

subCtrlTwo.$inject = ["$scope"];

function subCtrlTwo($scope) {

    $scope.getAddrress = function(addr) {

        $scope.$emit('addrBoom', addr);   
    }
}

http://jsfiddle.net/shushanthp/zp6v0rut/


Una chiusura è molto simile a un oggetto. Viene istanziato ogni volta che si chiama una funzione.

Lo scopo di una chiusura in JavaScript è lessicale, il che significa che tutto ciò che è contenuto nella funzione a cui appartiene la chiusura , ha accesso a qualsiasi variabile che è in essa.

Una variabile è contenuta nella chiusura se tu

  1. assegnarlo con var foo=1; o
  2. Scrivi e basta var foo;

Se una funzione interna (una funzione contenuta in un'altra funzione) accede a tale variabile senza definirla nel suo ambito con var, modifica il contenuto della variabile nella chiusura esterna .

Una chiusura sopravvive al runtime della funzione che lo ha generato. Se altre funzioni escono dalla chiusura / ambito in cui sono definite (ad esempio come valori di ritorno), quelle continueranno a fare riferimento a tale chiusura .

Esempio

function example(closure) {
  // define somevariable to live in the closure of example
  var somevariable = 'unchanged';

  return {
    change_to: function(value) {
      somevariable = value;
    },
    log: function(value) {
      console.log('somevariable of closure %s is: %s',
        closure, somevariable);
    }
  }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();

Produzione

somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged






javascript angularjs