从遗留代码调用 AngularJS

IT技术 javascript actionscript-3 externalinterface angularjs
2021-01-14 01:09:41

我正在使用 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>)。

谢谢!

6个回答

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

对于任何 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.
});
我无法angular.element(document.getElementById(divName)).scope()让它工作:我正在调用,但我无法从中调用任何函数,它只是在控制台中返回“未定义”。
2021-03-21 01:09:41
这有效,但我希望有某种方法可以从module直接进入它的范围 - 这可能吗?[ng-app]当我已经有了对module的引用时,不得不返回选择根节点似乎倒退了......
2021-03-30 01:09:41
即使我面临@Emil 上面描述的相同问题,它也返回未定义。有什么帮助吗?
2021-04-01 01:09:41
如果调试数据关闭,则 element().scope() 将不起作用,这是生产的建议。在这种情况下,这不会使它变得无用吗?这仅用于测试/调试。
2021-04-06 01:09:41
你不会想在 Angular 1.3 中这样做。Angular 团队不打算让我们对生产代码中的元素调用“.scope()”。它本来是一个调试工具。因此,从 Angular 1.3 开始,您可以将其关闭。Angular 将停止使用 jQuery 的 .data 函数将范围附加到元素。这将加速您的应用程序。此外,将范围交给 jquery 的缓存功能会造成内存泄漏。所以,你绝对应该关闭它,以加速你的应用程序。Angular 的站点有一个生产指南,您应该使用它来了解更多信息。
2021-04-08 01:09:41

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

如果要从遗留应用程序中调用 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/

我还在 Ottawa AngularJS 小组的幻灯片中展示了这一点(直接跳到最后 2 张幻灯片)

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

请注意,不鼓励仅提供链接的答案,所以答案应该是搜索解决方案的终点(相对于参考的另一个中途停留,随着时间的推移往往会变得陈旧)。请考虑在此处添加独立概要,保留链接作为参考。
2021-03-14 01:09:41
很好的补充说明。谢谢。
2021-03-19 01:09:41
美丽的解释!允许我通过这样做来规避表单验证:<input type="button" onclick="angular.element(this).scope().edit.delete();" value="delete">
2021-03-21 01:09:41

我发现的概念的最佳解释位于: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);
}); 
如果您使用 ng-view 并将您的视图拆分为它们自己的文件。你可以把 和id放在顶部的 HTML 元素中,然后做document.getElementById()那个 id。这使您可以访问该控制器的范围。方法/属性等......只是对鹅侠的评论提出了一个很好的观点。
2021-03-17 01:09:41
忽略我的问题。我能够通过使用 document.getElementById('any-Control-That-Has-An-NG-Directive').scope() 来完成这项工作。
2021-03-24 01:09:41
我知道这是一个非常古老的线程,但我想我遇到了这个问题。有没有人有任何代码可以显示如何遍历列表以找出要抓取的 DOM 元素?
2021-04-02 01:09:41
当应用程序和控制器共存于同一个元素中时,上述方法有效。对于将 ng-view 指令用于模板的更复杂的应用程序,您必须获取视图中的第一个元素,而不是整个应用程序的 DOM 元素。我不得不用 document.getElementsByClassName('ng-scope'); 遍历元素。节点列表以找出要抓取的正确范围 DOM 元素。
2021-04-06 01:09:41

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

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