Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get @vimeo/player to work on my Angular2/Typescript project?

Question:

How do I get @vimeo/player to work on my Angular2/Typescript project (specifically Ionic2) ?

Description:

Trying to get the vimeo player to work with Angular2/Typescript.

npm install --save @vimeo/player

According to their documentation the library can be used like so:

If you’re using a module bundler like webpack or rollup, the exported object will be the Player constructor (unlike the browser where it is attached to window.Vimeo):

import Player from '@vimeo/player';

const player = new Player('handstick', {
    id: 19231868,
    width: 640
});

player.on('play', function() {
    console.log('played the video!');
});

Which looks super promising ! But doesn't work.

What I've tried:

I've installed @vimeo/player and @types/vimeo__player I created a player component in my Ionic2 app.

player.ts:

import {Component, ViewChild} from '@angular/core';
import {NavController} from "ionic-angular/index";

//noinspection TypeScriptCheckImport,TypeScriptCheckImport
import Player from "@vimeo/player";


@Component({
  selector: 'player-component',
  templateUrl: 'player.html'
})
export class PlayerComponent {

  @ViewChild('player_container') playerContainer;
  private player: Player;

  constructor(public navCtrl: NavController){}

  ngAfterViewInit() {
    // child is set
    this.player = new Player(this.playerContainer);
    console.log(Player);
  }

}

I use view child, but I've also tried with the element's ID.

player.html

<div #player_container></div>

And get the following error:

Uncaught (in promise): TypeError: You must pass either a valid element or a valid id. Player@http://localhost:8100/build/main.js:102846:32 ngAfterViewInit@http://localhost:8100/build/main.js:74715:80 callProviderLifecycles@http://localhost:8100/build/main.js:11417:33 callElementProvidersLifecycles@http://localhost:8100/build/main.js:11392:35 callLifecycleHooksChildrenFirst@http://localhost:8100/build/main.js:11376:47 checkAndUpdateView@http://localhost:8100/build/main.js:12408:36 callWithDebugContext@http://localhost:8100/build/main.js:13462:47 detectChanges@http://localhost:8100/build/main.js:10474:81 _viewAttachToDOM@http://localhost:8100/build/main.js:43884:53 _transition@http://localhost:8100/build/main.js:43976:34 onInvoke@http://localhost:8100/build/main.js:4406:43 run@http://localhost:8100/build/polyfills.js:3:4146 http://localhost:8100/build/polyfills.js:3:13734 onInvokeTask@http://localhost:8100/build/main.js:4397:47 runTask@http://localhost:8100/build/polyfills.js:3:4841 o@http://localhost:8100/build/polyfills.js:3:1898 invoke@http://localhost:8100/build/polyfills.js:3:10674

As you can see it compiles but crashes at runtime.

@types/vimeo__player Just doesn't seem to be finished, and doesn't even seem to be noticed when I import @vimeo/player

The issue on github regarding vimeo__player seems show that this is true.

It looks like module resolution is correctly resolving it as a JS module, but only because it didn't find the types first. Are you sure you've correctly included those types? --listFiles would show you if it's lincluded.

Extras:

Issued opened on Vimeo's github player page.

like image 606
kemicofa ghost Avatar asked Jun 16 '17 13:06

kemicofa ghost


3 Answers

Your problem is not caused by @types/vimeo__player neither it is related to your build system/configuration.

TypeScript type definitions never, never, never affect runtime's behaviour. Even compile-time errors have no other effect than displaying red in the console, the JavaScript will still be emitted.

Looking at the stack trace you've got, we can also say that Player is effectively imported, and since you're saying that there is no compile-time error, everything is good on the build aspect of the things.

In fact, the error says it all: TypeError: You must pass either a valid element or a valid id..

Player says that it expects an HTMLElement.

The problem is, you are using @ViewChild() from Angular. This decorator will return a wrapper when you are querying on a native element. This wrapper is of type ElementRef, and has a property named nativeElement that contains the original, DOM element.

So instead of doing this:

this.player = new Player(this.playerContainer);

Do this:

this.player = new Player(this.playerContainer.nativeElement);

But you may now think "why TypeScript didn't produced a type error since I'm not passing a native element ?". That's a good question, I don't have enough data to be sure, but I think that your import may be incorrect.

Instead of:

//noinspection TypeScriptCheckImport,TypeScriptCheckImport
import Player from "@vimeo/player";

Can you try to do this?

import { Player } from '@vimeo/player';

Looking at the .d.ts file, it looks like that Player is a named export. But you're right, the type definitions of @vimeo/player are incomplete, or not in sync with the JavaScript library. You should be aware of that type of problems in TypeScript, although this does not happen everyday ;)

like image 117
Morgan Touverey Quilling Avatar answered Nov 19 '22 16:11

Morgan Touverey Quilling


For a standard typescript project this import statement works.

import * as Player from "@vimeo/player/dist/player.js";
like image 5
kemicofa ghost Avatar answered Nov 19 '22 16:11

kemicofa ghost


In case your ViewChild is undefined (due to a lazy load, etc), you can try this:

  • ViewChildren instead of ViewChild;
  • Wait DOM be available before running your code;

Code:

import { Component, ViewChildren } from '@angular/core';
import Player from "@vimeo/player";


@Component({
  selector: 'player-component',
  templateUrl: 'player.html'
})
export class PlayerComponent {

  private player: Player;
  @ViewChildren('player_container') playerContainer;

  ngAfterViewInit() {
    /* wait DOM be available */
    this.playerContainer.changes.subscribe(item => {
        if (this.playerContainer.length) {
            /* DOM AVAILABLE */
            this.player = new Player(this.playerContainer.first.nativeElement);

            this.player.on('play', function() {
                console.log('played the video!');
            });

            this.player.getVideoTitle().then(function(title) {
                console.log('title:', title);
            });
        }
    })
  }
}
like image 4
Daniel Loureiro Avatar answered Nov 19 '22 17:11

Daniel Loureiro