我正在使用 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 之外更新服务吗?控制器可以监听来自服务的事件吗?在一个 experiment (click for fiddle) 中,我似乎可以访问服务,但更新服务的数据不会反映在视图中(在示例中,<option>
应添加到 <select>
)。
谢谢!
var injector = angular.injector(['ng', 'MyApp']);
定位应用程序内的元素的情况下获得的。这样做会给您一个全新的上下文和一个重复的 myService
。这意味着您最终会得到服务和模型的两个实例,并且会将数据添加到错误的位置。您应该改为使用 angular.element('#ng-app').injector(['ng', 'MyApp'])
定位应用程序内的元素。此时,您可以使用 $apply 来包装模型更改。
从 Angular 外部到 Angular 的互操作与调试 Angular 应用程序或与第三方库集成相同。
对于任何 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“微应用”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 小组的幻灯片中展示了这一点(只需跳到最后两张幻灯片)
http://www.slideshare.net/peterdrinnan/angular-for-legacyapps
<input type="button" onclick="angular.element(this).scope().edit.delete();" value="delete">
我发现的对该概念的最佳解释位于此处: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);
});
id
放在顶部的 HTML 元素中,然后执行 document.getElementById()
该 ID。这使您可以访问该控制器的范围。方法/属性等......只是对 goosemanjack 的评论提出了一个很好的观点。
进一步的其他答案。如果您不想访问控制器中的方法但想直接访问服务,您可以执行以下操作:
// 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>
这将当前范围(赋予指令的链接函数)存储在全局“范围”对象中,该对象是所有范围的持有者。提供给指令属性的值用作此全局对象中范围的属性名称。
请参阅演示 here。正如我在演示中所展示的,当范围从全局“范围”对象中存储和删除时,您可以触发 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();
到目前为止,这是纯 Angular 和 javascript 面向服务的编程。但是遗留集成在这里:
<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();
配置我的应用程序可能会破坏应用程序。但是,如果您的应用程序了解范围并且可以依赖它而不经常更改,那么之前建议的方法是一种可行的方法。
希望这可以帮助。也欢迎任何反馈。
[ng-app]
根节点似乎是倒退...angular.element(document.getElementById(divName)).scope()
,但我无法从中调用任何函数,它只是在控制台中返回“未定义”。