Chiama AngularJS dal codice precedente

Uso AngularJS per creare controlli HTML che interagiscono con un’applicazione legacy Flex. Tutti i callback dall’app Flex devono essere collegati alla finestra DOM.

Ad esempio (in AS3)

ExternalInterface.call("save", data); 

Chiamerà

 window.save = function(data){ // want to update a service // or dispatch an event here... } 

Dall’interno della funzione di ridimensionamento JS vorrei inviare un evento che un controller può ascoltare. Sembra che creare un servizio sia la strada da percorrere. È ansible aggiornare un servizio al di fuori di AngularJS? Un controller può ascoltare gli eventi da un servizio? In un esperimento (click for fiddle) ho fatto sembrare che posso accedere a un servizio ma l’aggiornamento dei dati del servizio non si riflette nella vista (nell’esempio un dovrebbe essere aggiunto a ).

Grazie!

Interop da fuori angular a angular è lo stesso del debug dell’applicazione angular o dell’integrazione con la libreria di terze parti.

Per qualsiasi elemento DOM puoi farlo:

  • angular.element(domElement).scope() per ottenere l’ambito corrente per l’elemento
  • angular.element(domElement).injector() per ottenere l’iniettore dell’app corrente
  • angular.element(domElement).controller() per ottenere una angular.element(domElement).controller() di ng-controller .

Dall’iniettore è ansible ottenere una sospensione di qualsiasi servizio in un’applicazione angular. Allo stesso modo dall’ambito è ansible richiamare qualsiasi metodo che è stato pubblicato su di esso.

Tenere presente che qualsiasi modifica al modello angular o qualsiasi richiamo di metodo sull’ambito deve essere racchiusa in $apply() come questo:

 $scope.$apply(function(){ // perform any model changes or method invocations here on angular app. }); 

Misko ha dato la risposta corretta (ovviamente), ma alcuni di noi neofiti potrebbero averne bisogno ulteriormente.

Quando si tratta di chiamare il codice AngularJS all’interno delle app legacy, si pensi al codice AngularJS come a una “micro app” esistente all’interno di un contenitore protetto nell’applicazione legacy. Non è ansible effettuare chiamate direttamente (per una buona ragione), ma è ansible effettuare chiamate remote tramite l’object $ scope.

Per utilizzare l’object $ scope, è necessario ottenere l’handle di $ scope. Fortunatamente questo è molto facile da fare.

È ansible utilizzare l’id di qualsiasi elemento HTML all’interno del codice HTML “micro-app” di AngularJS per ottenere l’handle dell’app $ scope di AngularJS.

Ad esempio, diciamo che vogliamo chiamare un paio di funzioni all’interno del nostro controller AngularJS come sayHi () e sayBye (). Nel codice HTML di AngularJS (vista) abbiamo un div con l’id “MySuperAwesomeApp”. È ansible utilizzare il seguente codice, combinato con jQuery per ottenere l’handle di $ scope:

 var microappscope = angular.element($("#MySuperAwesomeApp")).scope(); 

Ora puoi chiamare le funzioni del tuo codice AngularJS tramite la maniglia dell’oscilloscopio:

 // we are in legacy code land here... microappscope.sayHi(); microappscope.sayBye(); 

Per rendere le cose più convenienti, puoi usare una funzione per afferrare l’handle dell’oscilloscopio ogni volta che vuoi accedervi:

 function microappscope(){ return angular.element($("#MySuperAwesomeApp")).scope(); } 

Le tue chiamate sarebbero quindi così:

 microappscope().sayHi(); microappscope().sayBye(); 

Puoi vedere un esempio di lavoro qui:

http://jsfiddle.net/peterdrinnan/2nPnB/16/

Ho anche mostrato questo in una presentazione per il gruppo Ottawa AngularJS (basta saltare alle ultime 2 diapositive)

http://www.slideshare.net/peterdrinnan/angular-for-legacyapps

La più grande spiegazione del concetto che ho trovato si trova qui: https://groups.google.com/forum/#!msg/angular/kqFrwiysgpA/eB9mNbQzcHwJ

Per farti risparmiare il clic:

 // get Angular scope from the known DOM element e = document.getElementById('myAngularApp'); scope = angular.element(e).scope(); // update the model with a wrap in $apply(fn) which will refresh the view for us scope.$apply(function() { scope.controllerMethod(val); }); 

Grazie al post precedente, posso aggiornare il mio modello con un evento asincrono.

 

Dichiaro il mio modello

 function Filters($scope) { $scope.filters = []; } 

E aggiorno il mio modello al di fuori del mio ambito

 ws.onmessage = function (evt) { dictt = JSON.parse(evt.data); angular.element(document.getElementById('control-panel')).scope().$apply(function(scope){ scope.filters = dictt.filters; }); }; 

Oltre alle altre risposte. Se non vuoi accedere ad un metodo in un controller ma vuoi accedere direttamente al servizio puoi fare qualcosa di simile a questo:

 // Angular code* : var myService = function(){ this.my_number = 9; } angular.module('myApp').service('myService', myService); // External Legacy Code: var external_access_to_my_service = angular.element('body').injector().get('myService'); var my_number = external_access_to_my_service.my_number 

Un modo più sicuro e performante, specialmente quando i dati di debug sono distriggersti, è utilizzare una variabile condivisa per contenere una funzione di callback. Il controller angular implementa questa funzione per restituire i suoi interni al codice esterno.

 var sharedVar = {} myModule.constant('mySharedVar', sharedVar) mymodule.controller('MyCtrl', [ '$scope','mySharedVar', function( $scope, mySharedVar) { var scopeToReturn = $scope; $scope.$on('$destroy', function() { scopeToReturn = null; }); mySharedVar.accessScope = function() { return scopeToReturn; } }]); 

Generalizzata come direttiva riutilizzabile:

Ho creato una direttiva “exposeScope” che funziona in modo simile ma l’utilizzo è più semplice:

 

Nota che, non ho testato l’on (‘scopeDestroyed’) quando l’elemento reale viene rimosso dal DOM. Se non funziona, l’triggerszione dell’evento sul documento stesso invece dell’elemento può essere d’aiuto. (vedi lo script app.js) nel plunker demo.

So che questa è una vecchia domanda, ma stavo guardando le opzioni per farlo di recente, quindi ho pensato di mettere le mie conclusioni qui nel caso fosse utile a chiunque.

Nella maggior parte dei casi, se è necessario che il codice legacy esterno interagisca con lo stato dell’interfaccia utente o il funzionamento interno dell’applicazione, un servizio potrebbe essere utile per astrarre tali modifiche. Se un codice esterno interagisce direttamente con il tuo controller angular, componente o direttiva, stai accoppiando la tua app pesantemente con il tuo codice legacy che è una ctriggers notizia.

Quello che ho finito per usare nel mio caso, è una combinazione di elementi globalmente accessibili al browser (cioè la finestra) e la gestione degli eventi. Il mio codice ha un motore di generazione di moduli intelligenti che richiede l’output JSON da un CMS per inizializzare i moduli. Ecco cosa ho fatto:

 function FormSchemaService(DOM) { var conf = DOM.conf; // This event is the point of integration from Legacy Code DOM.addEventListener('register-schema', function (e) { registerSchema(DOM.conf); }, false); // service logic continues .... 

Il servizio Schema modulo viene creato utilizzando l’iniettore angular come previsto:

 angular.module('myApp.services'). service('FormSchemaService', ['$window' , FormSchemaService ]) 

E nei miei controller: function () {‘use strict’;

 angular.module('myApp').controller('MyController', MyController); MyEncapsulatorController.$inject = ['$scope', 'FormSchemaService']; function MyController($scope, formSchemaService) { // using the already configured formSchemaService formSchemaService.buildForm(); 

Finora questa è pura programmazione angular e orientata ai servizi javascript. Ma l’integrazione legacy viene qui:

  

Ovviamente ogni approccio ha i suoi pregi e difetti. I vantaggi e l’utilizzo di questo approccio dipendono dall’interfaccia utente. Gli approcci precedentemente suggeriti non funzionano nel mio caso poiché il mio schema di modulo e il codice precedente non hanno controllo e conoscenza degli ambiti angolari. Quindi configurare la mia app basata su angular.element('element-X').scope(); potrebbe potenzialmente rompere l’app se cambiamo gli ambiti. Ma se la tua app ha conoscenze specifiche e può fare affidamento su di essa non cambiando spesso, ciò che viene suggerito in precedenza è un approccio praticabile.

Spero che questo ti aiuti. Qualsiasi feedback è anche il benvenuto.