Wywołaj AngularJS z kodu źródłowego

Używam AngularJS do tworzenia kontrolek HTML, które współdziałają ze starszą aplikacją Flex. Wszystkie wywołania zwrotne z aplikacji Flex muszą być dołączone do okna DOM.

Na przykład (w AS3)

ExternalInterface.call("save", data);

Wywoła

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

Z poziomu funkcji js resize chciałbym wysłać zdarzenie, które może usłyszeć kontroler. Wydaje się, że tworzenie usługi jest drogą do zrobienia. Czy możesz zaktualizować usługę spoza AngularJS? Czy kontroler może nasłuchiwać zdarzeń z usługi? W jednym eksperyment (kliknij po fiddle) {[12] } zrobiłem wygląda na to, że mogę uzyskać dostęp do usługi, ale aktualizacja danych usługi nie odbija się w widoku (w przykładzie należy dodać <option> do <select>).

Dzięki!
Author: chanafdo, 2012-05-08

7 answers

Interop z zewnątrz angular do angular jest taki sam jak debugowanie aplikacji angular lub integracja z biblioteką innych firm.

Dla dowolnego elementu DOM możesz to zrobić:

  • angular.element(domElement).scope() Aby uzyskać bieżący zakres dla elementu
  • angular.element(domElement).injector() Aby pobrać aktualną aplikację injector
  • angular.element(domElement).controller() aby zdobyć instancję ng-controller.
Z wtryskiwacza można uzyskać dostęp do dowolnej usługi w aplikacji kątowej. Podobnie z zakresu można wywołać dowolne metody, które zostały do niej opublikowane.

Należy pamiętać, że wszelkie zmiany w modelu kątowym lub jakiekolwiek wywołania metody na lunecie muszą być zawinięte w $apply() w następujący sposób:

$scope.$apply(function(){
  // perform any model changes or method invocations here on angular app.
});
 291
Author: Misko Hevery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-09 01:29:49

Misko dał poprawną odpowiedź (oczywiście), ale niektórzy z nas nowicjuszy mogą potrzebować jej dalszego uproszczenia.

Jeśli chodzi o wywołanie kodu AngularJS z poziomu starszych aplikacji, pomyśl o kodzie AngularJS jako "mikro aplikacji" istniejącej w chronionym kontenerze w starszej aplikacji. Nie można wykonywać połączeń bezpośrednio (z bardzo ważnego powodu), ale można wykonywać połączenia zdalne przy pomocy obiektu $scope.

Aby użyć obiektu $ scope, musisz uzyskać obsługę $scope. Na szczęście jest to bardzo łatwe do zrobienia.

Możesz użyć identyfikatora dowolnego elementu HTML w Twojej aplikacji AngularJS "micro-app" HTML, aby uzyskać obsługę aplikacji AngularJS $scope.

Jako przykład, powiedzmy, że chcemy wywołać kilka funkcji w naszym kontrolerze AngularJS, takich jak sayHi () i sayBye (). W AngularJS HTML (view) mamy div o id "MySuperAwesomeApp". Możesz użyć następującego kodu, w połączeniu z jQuery, aby uzyskać obsługę $scope:

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

Teraz ty może wywoływać funkcje kodu AngularJS za pomocą uchwytu zakresu:

// we are in legacy code land here...

microappscope.sayHi();

microappscope.sayBye();

Aby uczynić coś wygodniejszego, możesz użyć funkcji, aby chwycić uchwyt zakresu w dowolnym momencie, aby uzyskać do niego dostęp:

function microappscope(){

    return angular.element($("#MySuperAwesomeApp")).scope();

}

Twoje rozmowy wyglądałyby wtedy tak:

microappscope().sayHi();

microappscope().sayBye();

Możesz zobaczyć działający przykład tutaj:

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

Pokazałem to również w pokazie slajdów dla grupy Ottawa AngularJS (po prostu przejdź do ostatnich 2 slajdy)

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

 86
Author: Peter Drinnan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-29 15:45:20

Największe wyjaśnienie pojęcia, które znalazłem znajduje się tutaj: https://groups.google.com/forum/#! msg / angular/kqFrwiysgpA / eB9mNbQzcHwJ

Aby zapisać klikanie:

// 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);
}); 
 24
Author: Wiseman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-09 19:34:58

Dzięki poprzedniemu wpisowi mogę zaktualizować mój model o Zdarzenie asynchroniczne.

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

Oświadczam, że mój model

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

I aktualizuję mój model spoza mojego zakresu

ws.onmessage = function (evt) {
    dictt = JSON.parse(evt.data);
    angular.element(document.getElementById('control-panel')).scope().$apply(function(scope){
        scope.filters = dictt.filters;
    });
};
 13
Author: Guillaume Vincent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-08 01:43:15

Dalej do innych odpowiedzi. Jeśli nie chcesz uzyskać dostępu do metody w kontrolerze, ale chcesz uzyskać dostęp bezpośrednio do usługi, możesz zrobić coś takiego:

// 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 
 12
Author: Alec Hewitt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-24 09:29:23

Bardziej bezpiecznym i wydajnym sposobem, zwłaszcza gdy dane debugowania są wyłączone, jest użycie współdzielonej zmiennej do przechowywania funkcji zwrotnej. Twój kontroler kątowy implementuje tę funkcję, aby przywrócić jego wewnętrzne elementy do zewnętrznego kodu.

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

Uogólniona jako dyrektywa wielokrotnego użytku:

Stworzyłem dyrektywę 'exposeScope', która działa w podobny sposób, ale użycie jest prostsze:

<div ng-controller="myController" expose-scope="aVariableNameForThisScope">
   <span expose-scope='anotherVariableNameForTheSameScope" />
</div>

Przechowuje to bieżący zakres (który jest przypisany do funkcji link dyrektywy) w globalny obiekt "scopes", który jest uchwytem dla wszystkich zakresów. Wartość dostarczona do atrybutu dyrektywy jest używana jako nazwa właściwości zakresu w tym globalnym obiekcie.

Zobacz demo tutaj . Jak pokazałem w demo, możesz wywołać zdarzenia jQuery, gdy zakres jest przechowywany i usuwany z globalnego obiektu "zakresy".

<script type="text/javascript" >
    $('div').on('scopeLinked', function(e, scopeName, scope, allScopes) {
      // access the scope variable or the given name or the global scopes object
    }.on('scopeDestroyed', function(e, scopeName, scope, allScopes) {
      // access the scope variable or the given name or the global scopes object
    }

</script>

Zauważ, że nie testowałem on ('scopeDestroyed'), gdy rzeczywisty element jest usuwany z DOM. Jeśli nie zadziała, wywołanie zdarzenia na może pomóc sam dokument zamiast elementu. (Zobacz aplikację.js) skrypt w wersji demo.

 6
Author: Cagatay Kalan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-19 03:27:06

Wiem, że to stare pytanie, ale ostatnio patrzyłem na opcje, aby to zrobić, więc pomyślałem, że umieszczę moje ustalenia tutaj, na wypadek, gdyby było to przydatne dla kogokolwiek.

W większości przypadków, jeśli istnieje potrzeba zewnętrznego kodu starszego do interakcji ze stanem interfejsu użytkownika lub wewnętrznym działaniem aplikacji, Usługa może być przydatna do usunięcia tych zmian. Jeśli Zewnętrzny kod oddziałuje bezpośrednio z kontrolerem kątowym, komponentem lub dyrektywą, łączysz swój aplikacja mocno ze swoim starszym kodem, co jest złą wiadomością.

To, czego w moim przypadku użyłem, to połączenie globali dostępnych w przeglądarce (tj. okna) i obsługi zdarzeń. Mój kod ma inteligentny silnik generowania formularzy, który wymaga wyjścia JSON z CMS do inicjalizacji formularzy. Oto co zrobiłem:

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

Usługa schematu formularza jest tworzona przy użyciu wtryskiwacza kątowego zgodnie z oczekiwaniami:

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

I w moich kontrolerach: funkcja () { "use strict";

angular.module('myApp').controller('MyController', MyController);

MyEncapsulatorController.$inject = ['$scope', 'FormSchemaService'];

function MyController($scope, formSchemaService) {
    // using the already configured formSchemaService
    formSchemaService.buildForm(); 

Do tej pory jest to czyste programowanie angular i javascript service oriented. Ale dziedzictwo integracji przychodzi tutaj:

<script type="text/javascript">

   (function(app){
        var conf = app.conf = {
       'fields': {
          'field1: { // field configuration }
        }
     } ; 

     app.dispatchEvent(new Event('register-schema'));

 })(window);
</script>

Oczywiście każde podejście ma swoje zalety i wady. Zalety i zastosowanie tego podejścia zależy od twojego interfejsu użytkownika. Sugerowane wcześniej podejścia nie działają w moim przypadku, ponieważ mój schemat formularza i Kod źródłowy nie mają kontroli i wiedzy o zakresach kątowych. Dlatego konfigurowanie mojej aplikacji na podstawie angular.element('element-X').scope(); potencjalnie może złamać aplikację, jeśli zmienimy zakresy wokół. Ale jeśli aplikacja ma wiedzę na temat zakresu i może polegać na tym, że nie zmienia się często, to, co sugerowano wcześniej, jest realnym podejściem.

Mam nadzieję, że to pomoże. Wszelkie opinie są również mile widziane.
 3
Author: Shakus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-22 04:25:40