从旧代码中调用AngularJS

我正在使用AngularJS构build与旧版Flex应用程序交互的HTML控件。 Flex应用程序的所有callback都必须附加到DOM窗口。

例如(在AS3中)

ExternalInterface.call("save", data); 

将会通知

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

从JS resize函数中,我想派发一个控制器可以听到的事件。 看来创build一个服务是一条路。 你可以更新AngularJS以外的服务吗? 控制器可以监听来自服务的事件吗? 在一个实验中(点击小提琴)我似乎可以访问一个服务,但更新服务的数据并没有反映在视图(在这个例子中<option>应该被添加到<select> )。

谢谢!

从angular度外的Interop与debuggingangular度的应用相同或与第三方库集成。

对于任何DOM元素,你可以这样做:

  • angular.element(domElement).scope()获取元素的当前作用域
  • angular.element(domElement).injector()获取当前的应用程序注入器
  • angular.element(domElement).controller()获取ng-controller实例的持有者。

从注射器,您可以获得任何angular度应用服务。 与范围类似,您可以调用已经发布给它的任何方法。

请记住,angular度模型或作用域上的任何方法调用的任何更改都需要像这样包装在$apply()

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

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

当从传统应用程序中调用AngularJS代码时,可以将AngularJS代码看作是遗留应用程序中受保护容器内的“微应用程序”。 你不能直接调用它(出于很好的理由),但你可以通过$ scope对象进行远程调用。

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

您可以使用您的AngularJS“微应用”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/

我还在渥太华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); }); 

感谢上一篇文章,我可以用asynchronous事件更新我的模型。

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

进一步的其他答案。 如果您不想访问控制器中的某个方法,但想要直接访问该服务,则可以这样做:

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

特别是当debugging数据closures时,更安全和高效的方法是使用共享variables来保存callback函数。 您的angular度控制器实现此function将其内部返回到外部代码。

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

概括为一个可重用的指令:

我创build了一个以类似的方式工作的'exposeScope'指令,但用法更简单:

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

这将当前作用域(指向该指令的链接函数)存储在作为所有作用域的持有者的全局“作用域”对象中。 提供给指令属性的值用作此全局对象中作用域的属性名称。

在这里看到演示。 正如我在演示中展示的那样,当范围从全局“范围”对象中存储和删除时,可以触发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中删除实际元素时,我还没有testing过on('scopeDestroyed')。 如果它不起作用,触发文档本身而不是元​​素的事件可能会有所帮助。 (请参阅app.js)演示程序中的脚本。

我知道这是一个古老的问题,但我最近正在考虑select这样做,所以我想我把我的发现放在这里,以防万一对任何人有用。

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

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

 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(); 

到目前为止,这是纯粹的angular度和JavaScript面向服务的编程。 但遗留的整合来到这里:

 <script type="text/javascript"> (function(app){ var conf = app.conf = { 'fields': { 'field1: { // field configuration } } } ; app.dispatchEvent(new Event('register-schema')); })(window); </script> 

显然,每种方法都有其优点和缺点。 这种方法的优点和用途取决于您的用户界面。 以前build议的方法不适用于我的情况,因为我的表单模式和遗留代码没有angular度范围的控制和知识。 因此,根据angular.element('element-X').scope();configuration我的应用程序angular.element('element-X').scope(); 如果我们改变范围,可能会破坏应用程序。 但是,如果你的应用程序已经了解了范围界定的知识,并且可以依靠它而不是经常改变,那么以前的build议是一个可行的方法。

希望这可以帮助。 任何反馈也是受欢迎的。