Angular2-如何从应用程序外部调用组件函数


72

我正在使用具有回调的javascript对象。触发回调后,我想在Angular2组件中调用一个函数。

示例HTML文件。

    var run = new Hello('callbackfunction');

    function callbackfunction(){   
     // how to call the function **runThisFunctionFromOutside**
   }
   <script>
      System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {'js/app': {defaultExtension: 'ts'}} 
      });
      System.import('js/app/main')
            .then(null, console.error.bind(console));
    </script>

我的App.component.ts

import {Component NgZone} from 'angular2/core';
import {GameButtonsComponent} from './buttons/game-buttons.component';
@Component({
  selector: 'my-app',
  template: ' blblb'
})
export class AppComponent {

constructor(private _ngZone: NgZone){}

ngOnInit(){
    calledFromOutside() {
        this._ngZone.run(() => {
          this.runThisFunctionFromOutside();
    });
  }
  }
runThisFunctionFromOutside(){
   console.log("run");
}

我如何调用App.component.ts中的函数runThisFunctionFromOutside


您能给我们更多背景吗?你run反对在哪里发生?您的回调如何调用?谢谢!
Thierry Templier

在<my-app> </ my-app>外部的html中调用run。
罗尼尼奥

好的。和回调?
Thierry Templier

看起来您只需要使用闭包来访问回调内的组件,ngOnInit(){let vm = this; namedFromOutside(){vm._ngZone.run(()=> {vm.runThisFunctionFromOutside();}); }}
布兰登·索伦·库利(BrandonSørenCulley),

Answers:


61

另请参见如何公开公开angular 2方法?

构造组件后,将其分配给全局变量。然后,您可以从那里引用它并调用方法。不要忘记使用它,zone.run(() => { ... })以便Angular收到有关所需更改检测运行的通知。

 function callbackfunction(){   
   // window['angularComponentRef'] might not yet be set here though
   window['angularComponent'].zone.run(() => {
     runThisFunctionFromOutside(); 
   });
 }

constructor(private _ngZone: NgZone){
  window['angularComponentRef'] = {component: this, zone: _ngZone};
}

ngOnDestroy() {
  window.angularComponent = null;
}

柱塞示例1

在浏览器控制台中,您必须从切换到<topframe>plunkerPreviewTarget....因为Plunker在中执行代码iFrame。然后跑

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

要么

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

另一种方法

就像在Angular 2中解释的那样,将事件分发到Angular之外并在Angular中监听它们-打字稿功能与外部js库的通信

Plunker example2(来自注释)


2
如果缩小更改了名称,则最好分配一个函数引用而不是一个类引用(window.angularComponentRef = {zone: zone, /*component: this*/ componentFn: this.callFromOutside};)。
君特Zöchbauer


1
@GünterZöchbauer感谢您的回复。我遇到的问题是在儿童内部调用函数。我必须在每个构造函数中创建NgZone事件。
罗尼尼奥

1
升级到RC4后,Property 'angularComponentRef' does not exist on type 'Window'.启动npm时window.angularComponentRef引发错误。是否有其他替代方法来替换window.angularComponentRef
Nidhin TT

1
@GünterZöchbauer我遵循了以下步骤,但遇到了以下问题:stackoverflow.com/questions/39849369/linkedin-with-angular-2
Dheeraj Agrawal

71

我基本上遵循了这个答案,但是我不希望我的“外部”代码对NgZone有所了解。这是app.component.ts:

import {Component, NgZone, OnInit, OnDestroy} from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
  constructor(private ngZone: NgZone) {}

  ngOnInit() {
    window.my = window.my || {};
    window.my.namespace = window.my.namespace || {};
    window.my.namespace.publicFunc = this.publicFunc.bind(this);
  }

  ngOnDestroy() {
    window.my.namespace.publicFunc = null;
  }

  publicFunc() {
    this.ngZone.run(() => this.privateFunc());
  }

  privateFunc() {
    // do private stuff
  }
}

我还必须为TypeScript添加定义以扩展window对象。我把它放在types.d.ts中:

interface Window { my: any; }

现在,从控制台调用该函数非常简单:

my.namespace.publicFunc()

1
这对我有用,但是publicFunc总是被调用两次?
丹尼尔(Daniel)

1
这是更简洁的代码,对我有用,谢谢!
Caner

3
这是一个很好的解决方案,并且有效。我认为应该将其作为公认的答案。
肖恩

不必创建Window interface,您可以使用<any>类似方法使它保持动态(<any>window).my = (<any>window).my || {};
Pierre

6

下面是一个解决方案。

function callbackfunction(){   
   window.angularComponent.runThisFunctionFromOutside();
}
       <script>
          System.config({
            transpiler: 'typescript', 
            typescriptOptions: { emitDecoratorMetadata: true }, 
            packages: {'js/app': {defaultExtension: 'ts'}} 
          });
          System.import('js/app/main')
                .then(null, console.error.bind(console));
        </script>

我的App.component.ts

import {Component NgZone} from 'angular2/core';
import {GameButtonsComponent} from './buttons/game-buttons.component';
@Component({
    selector: 'my-app',
       template: ' blblb'
})
export class AppComponent {

  constructor(private _ngZone: NgZone){
  window.angularComponent = {runThisFunctionFromOutside: this.runThisFunctionFromOutside, zone: _ngZone};
}


    runThisFunctionFromOutside(){
      console.log("run");
    }
}

如何通过runThisFunctionFromOutside函数访问AppComponent中定义的变量?
Starwave'8

1
@Starwave:您需要将组件上下文绑定到回调函数:“ runThisFunctionFromOutside:this.runThisFunctionFromOutside.bind(this)”
gradosevic

完美的作品!谢谢
Manny

错误属性'angularComponent'在'Window
codemirror18

@codemirror(<any> window).angularComponent = {runThisFunctionFromOutside:this.runThisFunctionFromOutside,区域:_ngZone};
BernieSF

2

不使用全局变量的另一种方法是使用传递控制对象并将其属性绑定到要公开的变量和方法。

export class MyComponentToControlFromOutside implements OnChanges {

  @Input() // object to bind to internal methods
  control: {
    openDialog,
    closeDialog
  };

  ngOnChanges() {
    if (this.control) {
      // bind control methods to internal methods
      this.control.openDialog = this.internalOpenDialog.bind(this);
      this.control.closeDialog = this.internalCloseDialog;
    }
  }

  internalOpenDialog(): Observable<boolean> {
    // ...
  }

  internalCloseDialog(result: boolean) {
    // ...
  }
}
export class MyHostComponent {
   controlObject= {};
}
<my-component-to-control [control]="controlObject"></my-component-to-control>

<a (click)="controlObject.open()">Call open method</a>

非常干净的方法
Talha Junaid

1

使用fullCalendar库的回调'eventClick'时,我遇到了类似的情况,该回调从角度区域之外返回,导致我的应用程序具有部分和不可靠的效果。我能够将区域方法和对组件的闭包引用结合在一起,如下所示,以便引发输出事件。一旦我开始在zone.run()方法中执行事件,事件及其影响就可以再次预测并通过角度变化检测来识别。希望这对某人有帮助。

constructor(public zone: NgZone) { // code removed for clarity
}

ngOnInit() {
    this.configureCalendar();
}

private configureCalendar() {
    // FullCalendar settings
    this.uiConfig = {
        calendar: { // code removed for clarity

        }
    };

    this.uiConfig.calendar.eventClick = this.onEventClick();

}

private onEventClick() {
    const vm = this;

    return function (event, element, view) {
        vm.zone.run(() => {
            vm.onSequenceSelected.emit(event.sequenceSource);                    
        });

        return false;

    };
}

0

只需添加到@Dave Kennedy即可

现在,从控制台调用该函数非常简单:

my.namespace.publicFunc()

1)如果我们尝试从其他域访问组件的公共方法,则会陷入CORS问题(跨源问题,如果服务器和客户端代码都位于同一台机器上,则可以解决该问题)。

2)如果要使用javascript从服务器调用此方法,则必须使用window.opener.my.namespace.publicFunc()而不是window.my.namespace.publicFunc():

window.opener.my.namespace.publicFunc();


是什么my?那是字面值吗?还是一些特殊的钥匙?
redOctober13

您可以选择任何变量名来代替我的“” ngOnInit(){window.my = window.my || {}; window.my.namespace = window.my.namespace || {}; window.my.namespace.publicFunc = this.publicFunc.bind(this); }“”
Kailas,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.