Javascript 从遗留代码调用AngularJS

Javascript 从遗留代码调用AngularJS,javascript,actionscript-3,externalinterface,angularjs,Javascript,Actionscript 3,Externalinterface,Angularjs,我正在使用AngularJS构建与遗留Flex应用程序交互的HTML控件。来自Flex应用程序的所有回调都必须连接到DOM窗口 例如(在AS3中) 将呼叫 window.save = function(data){ // want to update a service // or dispatch an event here... } 在JS resize函数中,我想发送一个控制器可以听到的事件。看来,创建一个服务是一条路要走。你能从AngularJS之外更新服务吗?控制器

我正在使用AngularJS构建与遗留Flex应用程序交互的HTML控件。来自Flex应用程序的所有回调都必须连接到DOM窗口

例如(在AS3中)

将呼叫

window.save = function(data){
    // want to update a service 
    // or dispatch an event here...
}
在JS resize函数中,我想发送一个控制器可以听到的事件。看来,创建一个服务是一条路要走。你能从AngularJS之外更新服务吗?控制器能否侦听来自服务的事件?在其中一个例子中,我可以访问服务,但更新服务的数据不会反映在视图中(在示例中,应将
添加到


谢谢

从angular到angular的互操作与调试angular应用程序或与第三方库集成相同

对于任何DOM元素,都可以执行以下操作:

  • angular.element(doElement.scope()
    获取元素的当前作用域
  • angular.element(doElement).injector()
    获取当前应用程序注入器
  • angular.element(doElement).controller()
    获取
    ng controller
    实例
通过喷油器,您可以在角度应用中获得任何服务。类似地,您可以从范围中调用已发布到它的任何方法

请记住,对角度模型的任何更改或范围上的任何方法调用都需要包装在
$apply()
中,如下所示:

$scope.$apply(function(){
  // perform any model changes or method invocations here on angular app.
});
// 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 

多亏了上一篇文章,我可以用异步事件更新我的模型


  • {{filter.name}
我申报我的模型

函数过滤器($scope){
$scope.filters=[];
}
我从我的范围之外更新我的模型

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

我对这个概念的最好解释是:

要保存该文件,请单击:

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

Misko给出了正确的答案(显然),但我们中的一些新手可能需要进一步简化

当谈到从遗留应用程序中调用AngularJS代码时,请将AngularJS代码视为遗留应用程序中受保护容器中的“微型应用程序”。您不能直接调用它(原因很充分),但可以通过$scope对象进行远程调用

要使用$scope对象,需要获得$scope的句柄。幸运的是,这很容易做到

您可以使用AngularJS“micro app”HTML中任何HTML元素的id来获取AngularJS app$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();
您可以在此处看到一个工作示例:

我还在渥太华AngularJS小组的幻灯片中展示了这一点(只需跳到最后两张幻灯片)


进一步了解其他答案。 如果您不想访问控制器中的方法,但想直接访问服务,可以执行以下操作:

$scope.$apply(function(){
  // perform any model changes or method invocations here on angular app.
});
// 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 

更安全、更高效的方法是使用共享变量来保存回调函数,尤其是当调试数据处于关闭状态时。angular controller实现此函数以将其内部代码返回给外部代码

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>


我知道这是一个老问题,但最近我在寻找解决方法,所以我想我把我的发现放在这里,以防对任何人有用。

在大多数情况下,如果需要外部遗留代码与UI的状态或应用程序的内部工作进行交互,则可以使用服务来抽象这些更改。如果外部代码直接与您的角度控制器、组件或指令交互,那么您的应用程序与您的遗留代码严重耦合,这是个坏消息

在我的案例中,我最终使用的是浏览器可访问的全局变量(即窗口)和事件处理的组合。我的代码有一个智能表单生成引擎,它需要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 injector创建:

angular.module('myApp.services').
service('FormSchemaService', ['$window' , FormSchemaService ])
在我的控制器中: 函数(){ "严格使用",

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

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

function MyController($scope, formSchemaService) {
    // using the already configured formSchemaService
    formSchemaService.buildForm(); 
到目前为止,这是纯角度和面向javascript服务的编程。但传统的集成在这里:

<script type="text/javascript">

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

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

 })(window);
</script>

(功能(应用程序){
var conf=app.conf={
“字段”:{
'字段1:{//字段配置}
}
} ; 
app.dispatchEvent(新事件('register-schema'));
})(窗口);
显然,每种方法都有其优缺点。这种方法的优点和用途取决于您的UI。以前建议的方法在我的情况下不起作用,因为我的表单架构和遗留代码没有角度范围的控制和知识。因此,基于
angular.element('element-X').scope()配置我的应用程序;
如果我们改变范围,可能会破坏应用程序。但如果您的应用程序了解范围,并且可以依赖它不经常改变,那么前面建议的方法是可行的

希望这能有所帮助。欢迎提供任何反馈。