11
votes

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.

4

4 Answers

12
votes

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

4
votes

For a standard project this import statement works.

import * as Player from "@vimeo/player/dist/player.js";
4
votes

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);
            });
        }
    })
  }
}
0
votes

According to their documentation

When the library loads, it will scan your page for elements with Vimeo attributes. Each element must have at least a data-vimeo-id or data-vimeo-url attribute in order for the embed to be created automatically.

so basically it needs a div tag with either "data-vimeo-id" attribute or "data-video-url" attribute with valid values asiigned, before calling the player's constructor.

so You can use attribute binding to assign the video id(to data-vimeo-id) or video url (to data-video-url) to the div tag in your template file.

<div [attr.data-vimeo-id]="videoId"> </div>

and assign the video id of the video you want to embed to the variable "videoId" in the Typescript file (in ngOninit). same can be done with url also in that case [attr.data-vimeo-url]="videoUrl";