Angular2 - how to call component function from out

2019-01-01 10:30发布

I am using a javascript Object that has a callback. I want once the callback is fired to call a function inside an Angular2 component.

example HTML file.

    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>

My 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");
}

How can i call the function runThisFunctionFromOutside which is inside App.component.ts

标签: angular
6条回答
谁念西风独自凉
2楼-- · 2019-01-01 11:05

Just adding to @Dave Kennedy:

Calling the function from the console is now as simple as:

my.namespace.publicFunc()

1) If we try to access our component's public method from a different domain you will get caught into CORS issue (the cross origin problem, can be solved if both server and client code resides in same machine).

2) if you were to call this method from server using javascript, you will have to use window.opener.my.namespace.publicFunc() instead of window.my.namespace.publicFunc():

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

查看更多
后来的你喜欢了谁
3楼-- · 2019-01-01 11:09

I had a similar situation when using the callback 'eventClick' of the fullCalendar library, whose callbacks are returning from outside the angular zone, causing my application to have partial and unreliable effects. I was able to combine the zone approach and a closure reference to the component as seen below in order to raise an output event. Once I started executing the event inside of the zone.run() method the event and it's effects were once again predictable and picked up by angular change detection. Hope this helps someone.

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;

    };
}
查看更多
回忆,回不去的记忆
4楼-- · 2019-01-01 11:17

An other approach without using global variables is to use pass a control object and bind its properties to the variables and methods to expose.

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>
查看更多
路过你的时光
5楼-- · 2019-01-01 11:20

See also How do expose angular 2 methods publicly?

When the component is constucted make it assign itself to a global variable. Then you can reference it from there and call methods. Don't forget to use zone.run(() => { ... }) so Angular gets notified about required change detection runs.

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

Plunker example1

In the browser console you have to switch from <topframe> to plunkerPreviewTarget.... because Plunker executes the code in an iFrame. Then run

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

or

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

An alternative approach

would be to dispatch events outside Angular and listen to them in Angular like explained in Angular 2 - communication of typescript functions with external js libraries

Plunker example2 (from the comments)

查看更多
大哥的爱人
6楼-- · 2019-01-01 11:20

I basically followed this answer, but I didn't want my "outside" code to know anything about NgZone. This is 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
  }
}

I also had to add a definition for TypeScript to extend the window object. I put this in typings.d.ts:

interface Window { my: any; }

Calling the function from the console is now as simple as:

my.namespace.publicFunc()
查看更多
浮光初槿花落
7楼-- · 2019-01-01 11:20

Below is a solution.

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>

My 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");
    }
}
查看更多
登录 后发表回答