【问题标题】:How to expose angular 2 methods publicly?如何公开 angular 2 方法?
【发布时间】:2016-02-08 18:05:35
【问题描述】:

我目前正在将 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 列表,所以如果您也有这样做的提示,那将是一个额外的好处。 (我有想法,但欢迎其他人。)

【问题讨论】:

标签: javascript angular


【解决方案1】:

只需让组件在全局映射中注册,您就可以从那里访问它。

使用构造函数或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

在浏览器控制台中,您必须从&lt;topframe&gt; 切换到plunkerPreviewTarget....,因为Plunker 执行iFrame 中的代码。然后运行

window.angularComponentRef.zone.run(() => {window.angularComponentRef.component.callFromOutside('1');})

window.angularComponentRef.zone.run(() => {window.angularComponentRef.componentFn('2');})

【讨论】:

  • 好的,所以我需要为我所有的公共方法创建辅助方法。非常感谢您的帮助,顺便说一句。
  • 所以,在创建一个注册任务的服务时,我遇到了和我开始使用之前一样的问题 zone.run(()=&gt;{}) 方法已注册,我可以毫无问题地调用它,但是,似乎没有运行更改检测。上面的window.widget[name] = () =&gt; { window.zone.run(() =&gt; { scope[callbackMethod](); }); };scope是组件,我调用的方法是callbackMethod。有什么建议吗?
  • 我很欣赏 plunkr,但问题是我有一个外部服务正在将方法添加到 window.widget 对象上。我可以调用这些方法,但更改检测没有触发。看起来您的示例包含我在不使用外部服务时使用的内容。 (我可能会放弃该外部服务。)感谢您的帮助。
  • 现在角度不包括剃刀页面,所以 ngZone 不适用于这种情况,对吗?否则我的假设是错误的?
  • @k11k2 我不知道剃须刀页面是什么,也不知道它们与 ngZone 有什么关系
【解决方案2】:

我就是这样做的。我的组件如下所示。不要忘记导入 NgZone。这是这里最重要的部分。 NgZone 可以让 Angular 理解外部环境。通过区域运行函数允许您从在 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 的脚本标签到达这里。下面给出了我的 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 键,它将调用公开的方法,并且控制台上将打印“this works perfect”。

 window.angularComponentReference.zone.run(() =>
{window.angularComponentReference.componentFn(1);});

权利只是在此处作为参数传递的一些值。

【讨论】:

  • 我只是按照你的步骤结束了Cannot read property 'zone' of undefined 这发生在home.cshtml 中的ClickEvent 我的函数看起来像&lt;script&gt; function ClickEvent() { window.angularComponentReference.zone.run(() =&gt; { window.angularComponentReference.component.ClickEvents(); }); } &lt;/script&gt; ps: 在开发人员控制台中它可以工作很好。
  • 您是否将 Ngzone 导入到您的组件中?
  • 小心!!使用() =&gt; {}在角度外公开函数将不适用于IE。它不会被 Angular 转译。你应该使用function() { }
  • 我投了赞成票,因为您的答案比接受的恕我直言要清楚得多
  • 为什么需要zone,我可以直接调用window.angularComponentReference.componentFn(entitlement)。成功了吗?
【解决方案3】:

我正在检查代码,我发现 Zone 可能不是必需的。 没有 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>

这对我有用。

【讨论】:

    【解决方案4】:

    问题在于 Angular 的组件被转译为不像常规 JavaScript 代码那样容易访问的模块。访问模块功能的过程取决于模块的格式。

    Angular2 类可以包含无需实例化新对象即可定义的静态成员。您可能希望将代码更改为:

    @component({...})
    class MyTest {
        private static text: string = '';
        public static setText(text:string) {
            this.text = text;
        }
    }
    

    【讨论】:

    • 难道我还需要一种公开公开组件的方法吗?
    • 要访问 Angular 之外的组件,您应该查看已转译的 JavaScript。通常,网页通过访问加载器来加载组件(参见System.importSystemJS)。
    • 默认情况下无法访问通过 systemjs 加载的组件,查看转译的 js 也无济于事,因为 js 正在使用 system.register 加载。 Angular(或 Angular 等)甚至在全局范围内都不可用,(stackoverflow.com/questions/34779126/…)我们不会在生产中使用 systemjs。
    【解决方案5】:

    超级简单的解决方案!!用外部别名保存组件或函数

    declare var exposedFunction;
    @Component({
      templateUrl: 'app.html'
    })
    export class MyApp {
        constructor(public service:MyService){
        exposedFunction = service.myFunction;
    }
    

    在 index.html 中添加头部

    <script>
        var exposedFunction;
    </script>
    

    内部暴露函数不要使用这个。如果需要参数,则必须使用闭包才能使其工作

    这在 ionic 中特别有用,可以在 Web 而不是设备上测试设备通知

    【讨论】:

    • 那么如何从android调用它?
    • 同理,在你的web文件中添加@MohammadRezaMrg,index.html和你暴露的函数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 2016-10-24
    • 2017-12-13
    • 1970-01-01
    相关资源
    最近更新 更多