5

I have a external js library on my angular app, I added it as a global script on the angular-cli.json scripts array. Its working fine, but I need to assign some functions as response to events of this library. This library has an Display object which has some events:

Display.onplay
Display.onpause

How can I listen to these events in my angular component.ts ?

In plain JavaScript web application is just assign it to a function like:

  Display.onplay = function () { console.log('play'); }

But on angular I have no idea if its possible to do it.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
gog
  • 11,788
  • 23
  • 67
  • 129
  • It should work, but make sure to define the callback as an arrow function, to avoid [problems](https://stackoverflow.com/q/20279484/1009922) with `this` inside the callback. – ConnorsFan Jan 10 '18 at 19:57
  • but how can I assign it outside of a method? I will get some compilation errors if I type just like that in typescript. – gog Jan 10 '18 at 19:59
  • Maybe you can use `declare var Display: any;` in one of the class files (e.g. the app component, or a service), and assign the callback in the class constructor. – ConnorsFan Jan 10 '18 at 20:13

2 Answers2

3

It is possible and appropriate to access external Javascript libraries from an Angular application. There are some issues to keep in mind however.

Type Declarations

I will get some compilation errors if I type just like that in typescript.

This is common in Typescript. There are a couple of ways to fix this issue.

The first (and likely best) approach is to include a Typescript type declaration (.d.ts) file for the Display library in your project. If this is a popular third-party library it may already be available as an npm package called @types/[PACKAGE_NAME]. If it is not available you can write a type declaration. More information about creating and including type declarations can be found in the Typescript Documentation.

The second approach is to simply use (Display as any).onplay or (Display as any).onpause to avoid compilation errors.

Unit Testing

Placing this code in your top-level component may suffice for your needs, but I doubt it. This restricts where the Display library can be used.

I suggest wrapping the library in a well designed service. Using a service allows the Display library to be accessed by multiple components/services.

You may be unit testing the code that relies on the Display library. If this is the case the appropriate place to use (Display as any).onplay = ... would definitely be in a service. Services make it easier to stub the functionality of the third-party libraries.

Here's an untested example service:

import { Injectable } from '@angular/core';

export interface IDisplayService {
    onPlay(callback: () => void): void;
    onPause(callback: () => void): void;
}

@Injectable()
export class DisplayService implements IDisplayService {
    private onPlayCallback: () => void;
    private onPauseCallback: () => void;

    constructor() {
        if (!Display) {
            throw new Error('Display library is required');
        }

        (Display as any).onplay = () => {
            if (this.onPlayCallback) { this.onPlayCallback(); }
        };
        (Display as any).onpause = () => {
            if (this.onPauseCallback) { this.onPauseCallback(); }
        };
    }

    // Using a function allows you to register multiple callbacks
    // if you choose to allow it later on.
    onPlay(callback: () => void): void {
        this.onPlayCallback = callback;
    }

    onPause(callback: () => void): void {
        this.onPauseCallback = callback;
    }
}
Community
  • 1
  • 1
Joe Hawkins
  • 9,803
  • 2
  • 21
  • 28
1

Another aproach using a service and observable of the service an code in your app.component

app.component

declare var Display:any //<--declare the variable
@component(..)

export class AppComponent {
  constructor(private outEventService:OutEventService) {
  }
  Display.onplay (){   //the function like javascript only call function of service
     this.outEventService.sendEvent("play");
  }
  Display.onpause (){
     this.outEventService.sendEvent("pause");
  }
}

outEventService

export class OutEventService{

    private listeningSource:Subject<any>=new Subject<any>();
    displayEvent:Observable<any>=this.listeningSource.asObservable();

    constructor() {
    }

    sendEvent(evento:any)  //Simply make a change in the observable
    {
        this.listeningSource.next(evento);
    }
}

A component that subscribe event

constructor(private ngZone: NgZone,
    private outEventService: outEventService) {
  }
ngOnInit() {
this.outEventService.displayEvent.subscribe((evento: any) => {
      if (evento == "pause") {  
           do something
      }
      if (evento == "other") {  //Sometimes you must use ngZone to angular take account the change
        this.ngZone.run(() => {
            do something 
        })
      }
    });
Eliseo
  • 50,109
  • 4
  • 29
  • 67