我目前正致力于将Backbone项目移植到Angular 2项目(显然有很多变化),其中一项项目要求需要公开访问某些方法。
一个简单的例子:
组件
@component({...})
class MyTest {
private text:string = '';
public setText(text:string) {
this.text = text;
}
}
显然,我可以<button (click)="setText('hello world')>Click me!</button>
,我也希望这样做。但是,我希望能够公开访问它。
喜欢这个
<button onclick="angular.MyTest.setText('Hello from outside angular!')"></click>
或者
// in the js console
angular.MyTest.setText('Hello from outside angular!');
无论哪种方式,我希望公开曝光方法,以便可以从angular 2应用程序外部调用。
这是我们在骨干网上所做的事情,但我想我的Google foo不够强大,无法使用angular找到一个好的解决方案。
我们宁愿只公开一些方法并列出公共api,所以如果你有这方面的提示,那将是一个额外的好处。 (我有想法,但欢迎其他人。)
答案 0 :(得分:23)
只需让组件在全局地图中注册,您就可以从那里访问它。
使用构造函数或ngOnInit()
或任何其他lifecycle hooks来注册组件,并使用ngOnDestroy()
取消注册。
当您从Angular外部调用Angular方法时,Angular无法识别模型更改。这就是Angulars NgZone
的用途。
要获得对Angular区域的引用,只需将其注入构造函数
constructor(zone:NgZone) {
}
您也可以在全局对象中使zone
本身可用,或者只是在区域内的组件内执行代码。
例如
calledFromOutside(newValue:String) {
this.zone.run(() => {
this.value = newValue;
});
}
或使用全局区域引用,如
zone.run(() => { component.calledFromOutside(newValue); });
https://plnkr.co/edit/6gv2MbT4yzUhVUfv5u1b?p=preview
在浏览器控制台中,您必须从<topframe>
切换到plunkerPreviewTarget....
,因为Plunker会在iFrame
中执行代码。然后运行
window.angularComponentRef.zone.run(() => {window.angularComponentRef.component.callFromOutside('1');})
或
window.angularComponentRef.zone.run(() => {window.angularComponentRef.componentFn('2');})
答案 1 :(得分:12)
这就是我做到的。我的组件如下。别忘了导入NgZone。这是最重要的部分。 NgZone让角度理解外部环境。通过区域运行功能允许您从在Angular区域外执行的任务重新进入Angular区域。我们在这里需要它,因为我们正在处理一个不在角区域内的外部呼叫。
import { Component, Input , NgZone } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'example',
templateUrl: './example.html',
})
export class ExampleComponent {
public constructor(private zone: NgZone, private router: Router) {
//exposing component to the outside here
//componentFn called from outside and it in return calls callExampleFunction()
window['angularComponentReference'] = {
zone: this.zone,
componentFn: (value) => this.callExampleFunction(value),
component: this,
};
}
public callExampleFunction(value: any): any {
console.log('this works perfect');
}
}
现在让我们从外面调用它。在我的情况下,我想通过我的index.html.my index.html的脚本标记到达这里,如下所示。
<script>
//my listener to outside clicks
ipc.on('send-click-to-AT', (evt, entitlement) =>
electronClick(entitlement));;
//function invoked upon the outside click event
function electronClick(entitlement){
//this is the important part.call the exposed function inside angular
//component
window.angularComponentReference.zone.run(() =
{window.angularComponentReference.componentFn(entitlement);});
}
</script>
如果您只是在开发者控制台中键入以下内容并按Enter键,它将调用公开的方法,并且“这个工作完美”将打印在控制台上。
window.angularComponentReference.zone.run(() =>
{window.angularComponentReference.componentFn(1);});
权利只是一些在此处作为参数传递的值。
答案 2 :(得分:4)
我正在检查代码,而且我已经面临区域可能不是必需的。 没有NgZone,它运作良好。
在组件构造函数中执行以下操作:
constructor(....) {
window['fncIdentifierCompRef'] = {
component = this
};
}
在根脚本中试试这个:
<script>
function theGlobalJavascriptFnc(value) {
try {
if (!window.fncIdentifierCompRef) {
alert('No window.fncIdentifierCompRef);
return;
}
if (!window.fncIdentifierCompRef.component) {
alert('No window.fncIdentifierCompRef.component');
return;
}
window.fncIdentifierCompRef.component.PublicCmpFunc(value);
} catch(ex) {alert('Error on Cmp.PublicCmpFunc Method Call')}
}
</script>
这对我有用。
答案 3 :(得分:1)
问题在于Angular的组件被转换为不像常规JavaScript代码那样易于访问的模块。访问模块功能的过程取决于模块的格式。
Angular2类可以包含可以在不实例化新对象的情况下定义的静态成员。您可能希望将代码更改为:
imageNames = dir(fullfile(workingDir,'*.png'));
答案 4 :(得分:0)
超级简单的解决方案!!使用外部别名保存组件或功能
declare var exposedFunction;
@Component({
templateUrl: 'app.html'
})
export class MyApp {
constructor(public service:MyService){
exposedFunction = service.myFunction;
}
在index.html头上添加
<script>
var exposedFunction;
</script>
内部公开功能请勿使用。参数,如果需要它们,则必须使用闭包使其起作用
这在离子模式下尤其有用,它可以测试Web上的设备通知而不是设备上的通知