javascript - Anropa AngularJS från äldre kod
Jag använder AngularJS för att bygga HTML-kontroller som interagerar med en äldre Flex-applikation. Alla återanrop från Flex-appen måste kopplas till DOM-fönstret.
Till exempel (i AS3)
ExternalInterface.call("save", data);
Kommer att ringa
window.save = function(data){
// want to update a service
// or dispatch an event here...
}
Från inom JS resize-funktionen skulle jag vilja skicka ett event som en controller kan lyssna på. Det verkar som att skapa en service är vägen att gå. Kan du uppdatera en service från utsidan av AngularJS? Kan en controller lyssna efter event från en service? I ett experiment (klicka för fiddle) jag gjorde verkar det som att jag kan komma åt en service men att uppdatera servisens data inte återspeglas i vyn (i exemplet borde en <option> läggas till i <select>).
Tack!
Svar #1
Interop från utanför Angular till Angular är samma som att felsöka en Angular-applikation eller integrera med ett tredjepartsbibliotek.
För vilket DOM-element som helst kan du göra detta:
angular.element(domElement).scope()för att få det aktuella omfånget för elementetangular.element(domElement).injector()för att få den nuvarande app-injektornangular.element(domElement).controller()för att få tag pång-controller-instansen.
Från injektorn kan du få tillgång till vilken tjänst som helst i en Angular-applikation. På samma sätt kan du från scopet anropa vilka metoder som helst som har publicerats till det.
Tänk på att eventuella ändringar i den angulara modellen eller alla metodanrop på scope måste omslutas med $apply() på detta sätt:
$scope.$apply(function(){
// perform any model changes or method invocations here on angular app.
});
Svar #2
Misko gav det rätta svaret (uppenbarligen), men några av oss nybörjare kan behöva det förenklat ytterligare.
När det gäller att anropa AngularJS-kod från äldre appar, tänk på AngularJS-koden som en "mikroapp" som existerar inom en skyddad container i din äldre applikation. Du kan inte göra anrop till den direkt (av mycket goda skäl), men du kan göra fjärranrop via $scope-objektet.
För att använda $scope-objektet behöver du få tag på handtaget för $scope. Lyckligtvis är detta mycket lätt att göra.
Du kan använda id:t för vilket HTML-element som helst inom din AngularJS "mikro-app" HTML för att få handtaget till AngularJS appens $scope.
Som ett exempel, låt oss säga att vi vill kalla på ett par funktioner inom vår AngularJS-kontroller såsom sayHi() och sayBye(). I AngularJS HTML (vy) har vi en div med id "MySuperAwesomeApp". Du kan använda följande kod, kombinerad med jQuery för att få handtaget till $scope:
var microappscope = angular.element($("#MySuperAwesomeApp")).scope();
Nu kan du anropa dina AngularJS-kodfunktioner via scope-handtaget:
// we are in legacy code land here...
microappscope.sayHi();
microappscope.sayBye();
För att göra saker mer bekväma kan du använda en funktion för att ta tag i scope-handtaget när som helst du vill komma åt det:
function microappscope(){
return angular.element($("#MySuperAwesomeApp")).scope();
}
Dina samtal skulle då se ut så här:
microappscope().sayHi();
microappscope().sayBye();
Du kan se ett fungerande exempel här:
http://jsfiddle.net/peterdrinnan/2nPnB/16/
Jag visade också detta i en presentation för Ottawa AngularJS-gruppen (hoppa bara till de två sista bilderna)
http://www.slideshare.net/peterdrinnan/angular-for-legacyapps
Svar #3
Den bästa förklaringen av konceptet jag har hittat finns här: https://groups.google.com/forum/#!msg/angular/kqFrwiysgpA/eB9mNbQzcHwJ
För att spara dig klickandet:
// 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);
});
Svar #4
Ytterligare till de andra svaren. Om du inte vill komma åt en metod i en controller men vill komma åt tjänsten direkt kan du göra något sådant här:
// 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
Svar #5
Tack vare det tidigare inlägget kan jag uppdatera min modell med ett asynkront evenemang.
<div id="control-panel" ng-controller="Filters">
<ul>
<li ng-repeat="filter in filters">
<button type="submit" value="" class="filter_btn">{{filter.name}}</button>
</li>
</ul>
</div>
Jag deklarerar min modell
function Filters($scope) {
$scope.filters = [];
}
Och jag uppdaterar min modell utanför mitt område
ws.onmessage = function (evt) {
dictt = JSON.parse(evt.data);
angular.element(document.getElementById('control-panel')).scope().$apply(function(scope){
scope.filters = dictt.filters;
});
};
