[javascript] 레거시 코드에서 AngularJS 호출

AngularJS를 사용하여 레거시 Flex 응용 프로그램과 상호 작용하는 HTML 컨트롤을 작성하고 있습니다. Flex 앱의 모든 콜백은 DOM 창에 연결해야합니다.

예를 들어 (AS3에서)

ExternalInterface.call("save", data);

전화 할 것이다

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

JS 크기 조정 기능 내에서 컨트롤러가들을 수있는 이벤트를 전달하고 싶습니다. 서비스를 만드는 것이 갈 길인 것 같습니다. AngularJS 외부에서 서비스를 업데이트 할 수 있습니까? 컨트롤러가 서비스의 이벤트를 수신 할 수 있습니까? 한 실험 (피들 클릭) 에서 서비스에 액세스 할 수있는 것처럼 보이지만 서비스 데이터 업데이트는보기에 반영되지 않습니다 (예 :에 <option>추가해야 함 <select>).

감사!



답변

각도 외부에서 각도로의 Interop은 각도 응용 프로그램을 디버깅하거나 타사 라이브러리와 통합하는 것과 같습니다.

모든 DOM 요소에 대해 다음을 수행 할 수 있습니다.

  • angular.element(domElement).scope() 요소의 현재 범위를 가져옵니다.
  • angular.element(domElement).injector() 현재 앱 인젝터를 얻으려면
  • angular.element(domElement).controller()ng-controller인스턴스 를 확보 합니다.

인젝터에서 각도 어플리케이션의 모든 서비스를 유지할 수 있습니다. 마찬가지로 범위에서 게시 된 모든 메서드를 호출 할 수 있습니다.

각도 모델에 대한 변경 사항이나 범위에서 메서드 호출은 다음 $apply()과 같이 래핑해야합니다 .

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


답변

Misko가 정답을 줬지만, 우리 중 일부는 더 단순화해야 할 수도 있습니다.

레거시 앱 내에서 AngularJS 코드를 호출 할 때는 AngularJS 코드를 레거시 애플리케이션의 보호 된 컨테이너 내에 존재하는 “마이크로 앱”이라고 생각하십시오. 직접 호출 할 수는 없지만 (정당한 이유로) $ scope 객체를 통해 원격 호출을 할 수 있습니다.

$ scope 객체를 사용하려면 $ scope 핸들을 가져와야합니다. 다행히도 이것은 매우 쉽습니다.

AngularJS “micro-app”HTML에서 HTML 요소의 id를 사용하여 AngularJS 앱 $ scope의 핸들을 얻을 수 있습니다.

예를 들어 AngularJS 컨트롤러 내에서 sayHi () 및 sayBye ()와 같은 몇 가지 함수를 호출하려고한다고 가정합니다. AngularJS HTML (보기)에는 ID가 “MySuperAwesomeApp”인 div가 있습니다. 다음 코드를 jQuery와 결합하여 $ scope의 핸들을 얻을 수 있습니다.

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

이제 범위 핸들을 통해 AngularJS 코드 함수를 호출 할 수 있습니다.

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

microappscope.sayHi();

microappscope.sayBye();

보다 편리한 작업을 위해 함수를 사용하여 액세스하려는 경우 언제든지 범위 핸들을 잡을 수 있습니다.

function microappscope(){

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

}

그러면 귀하의 전화는 다음과 같습니다 :

microappscope().sayHi();

microappscope().sayBye();

여기에 실제 예제가 있습니다.

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

또한 Ottawa AngularJS 그룹의 슬라이드 쇼에서 이것을 보여주었습니다 (마지막 2 슬라이드로 건너 뛰십시오)

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


답변

내가 찾은 개념에 대한 가장 큰 설명은 https://groups.google.com/forum/#!msg/angular/kqFrwiysgpA/eB9mNbQzcHwJ 에 있습니다.

클릭을 저장하려면 다음을 수행하십시오.

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


답변

다른 답변에 더. 컨트롤러의 메소드에 액세스하지 않고 서비스에 직접 액세스하려는 경우 다음과 같이 할 수 있습니다.

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


답변

이전 게시물 덕분에 비동기 이벤트로 모델을 업데이트 할 수 있습니다.

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

내 모델을 선언합니다

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

그리고 내 범위 밖에서 모델을 업데이트합니다.

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


답변

특히 디버그 데이터가 꺼져있을 때 더 안전하고 성능이 좋은 방법은 공유 변수를 사용하여 콜백 함수를 유지하는 것입니다. 각도 컨트롤러는이 함수를 구현하여 내부 코드를 외부 코드로 반환합니다.

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

재사용 가능한 지시어로 일반화되었습니다.

비슷한 방식으로 작동하는 ‘exposeScope’지시문을 만들었지 만 사용법이 더 간단합니다.

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

이것은 현재 범위 (지시문의 링크 함수에 제공됨)를 모든 범위의 홀더 인 전역 ‘scopes’객체에 저장합니다. 지시문 속성에 제공된 값은이 전역 객체에서 범위의 속성 이름으로 사용됩니다.

여기 데모를 참조 하십시오 . 데모에서 알 수 있듯이 범위가 전역 ‘scopes’객체에서 저장되고 제거되면 jQuery 이벤트를 트리거 할 수 있습니다.

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

실제 요소가 DOM에서 제거 될 때 on ( ‘scopeDestroyed’)을 테스트하지 않았습니다. 작동하지 않으면 요소 대신 문서 자체에서 이벤트를 트리거하는 것이 도움이 될 수 있습니다. 데모 플 런커의 (app.js 참조) 스크립트


답변

나는 이것이 오래된 질문이라는 것을 알고 있지만 최근에 이것을 할 수있는 옵션을 찾고 있었으므로 누군가에게 도움이 될 수 있도록 여기에 찾은 것을 여기에 넣었다고 생각했습니다.

대부분의 경우 외부 레거시 코드가 UI 상태 또는 응용 프로그램의 내부 작업과 상호 작용해야하는 경우 이러한 변경 사항을 추상화하는 데 서비스가 유용 할 수 있습니다. 외부 코드가 각도 컨트롤러, 구성 요소 또는 지시문과 직접 ​​상호 작용하는 경우 나쁜 소식 인 레거시 코드와 앱이 크게 결합됩니다.

필자의 경우에 사용했던 것은 브라우저 액세스 가능한 전역 (예 : window)과 이벤트 처리의 조합입니다. 내 코드에는 스마트 양식 생성 엔진이있어 양식을 초기화하기 위해 CMS의 JSON 출력이 필요합니다. 내가 한 일은 다음과 같습니다.

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

양식 스키마 서비스는 예상대로 각도 인젝터를 사용하여 작성됩니다.

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

그리고 내 컨트롤러에서 : function () { ‘use strict’;

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

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

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

지금까지 이것은 순수한 각도 및 자바 스크립트 서비스 지향 프로그래밍입니다. 그러나 레거시 통합은 다음과 같습니다.

<script type="text/javascript">

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

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

 })(window);
</script>

분명히 모든 접근 방식에는 장점과 단점이 있습니다. 이 방법의 장점과 사용은 UI에 따라 다릅니다. 내 양식 스키마와 레거시 코드에는 각도 범위에 대한 제어 및 지식이 없으므로 이전에 제안 된 방법은 작동하지 않습니다. 따라서 angular.element('element-X').scope();
범위를 변경하면 앱을 기반으로 구성 하면 앱이 중단 될 수 있습니다. 그러나 응용 프로그램이 범위 지정에 대한 지식을 가지고 있으며 자주 변경되지 않는 응용 프로그램에 의존 할 수 있다면 이전에 제안 된 것은 실행 가능한 접근법입니다.

도움이 되었기를 바랍니다. 모든 의견도 환영합니다.