In the first implementation, I used angular2 without server rendering for creating a web player with video.js library and it's "videojs-resolution-switcher" plugin.
I created a directive for initializing videojs element based on component ngOnInitView and load js files directly in base html file (end of body).
Everything was correct and player worked as expected.
Then I started to setting up angular2-universal and server rendering. There was some problems about using browser specific features that I handled them with "isBrowser" tool.
But now I have a problem with videojs-resolution-switcher. Even with old configs in browser's console the error is:
Unable to find plugin: videoJsResolutionSwitcher
this.updateSrc is not a function
TypeError: this.updateSrc is not a function
at Player.<anonymous> (http://localhost:3000/main.bundle.js:95154:22)
at Player.<anonymous> (http://localhost:3000/main.bundle.js:5555:14)
at Array.forEach (native)
at Player.<anonymous> (http://localhost:3000/main.bundle.js:5554:20)
at bound (http://localhost:3000/main.bundle.js:8285:15)
at ZoneDelegate.invokeTask (http://localhost:3000/main.bundle.js:128033:31)
at Object.onInvokeTask (http://localhost:3000/main.bundle.js:38985:37)
at ZoneDelegate.invokeTask (http://localhost:3000/main.bundle.js:128032:36)
at Zone.runTask (http://localhost:3000/main.bundle.js:127836:47)
at ZoneTask.invoke (http://localhost:3000/main.bundle.js:128086:38)
at data.args.(anonymous function) (http://localhost:3000/main.bundle.js:129197:25)
I tried to require the videoJsResolutionSwitcher in directive, but it returns empty object (because it's not exported). Then I changed the plugin code to export the function but nothings changed just the error about updateSrc function was resolved.
I tried to import js file like this:
import '../../node_modules/videojs-resolution-switcher/lib/videojs-resolution-switcher.js';
But at the compile time an error raised about "undefining window" in videojs resolution switcher code.
videojs.ts directive:
import { Component, Directive, ElementRef, Input, Output, EventEmitter } from '@angular/core';
import { Subject } from 'rxjs/Rx';
let videojs = require('video.js');
import { isBrowser } from "angular2-universal";
@Component({
selector: '[hiVideoJs]',
host: {
class: 'video-js vjs-default-skin vjs-big-play-centered',
'[attr.poster]': 'poster'
},
template: ``
})
export class VideoJsDirective {
@Input()
private col;
@Input()
private poster;
@Input()
private sources: Array<string> = new Array<string>();
@Input()
private options: any = {};
@Input()
private mute: boolean = false;
@Input()
private endEvent: Subject<boolean>;
@Output()
private fullscreen: EventEmitter<{}> = new EventEmitter();
@Output()
private created: EventEmitter<{}> = new EventEmitter();
constructor(private element: ElementRef) {
}
ngAfterViewInit() {
// require('videojs-resolution-switcher')();
let width;
if (isBrowser)
width = this.col.clientWidth - ($(this.col).outerWidth() - $(this.col).width());
else
width = this.col.clientWidth;
var that = this;
this.options.width = width;
this.options.nativeControlsForTouch = false;
this.options.plugins = {
videoJsResolutionSwitcher: {
default: 'high',
dynamicLabel: true
}
};
var that = this;
if (isBrowser) {
let player = videojs(this.element.nativeElement, this.options, function () {
this.updateSrc(that.sources);
this.muted(that.mute);
if (that.endEvent)
this.on('ended', a => {
that.endEvent.next(true);
});
this.controlBar.fullscreenToggle.on('click', a => {
that.fullscreen.emit(true);
});
this.controlBar.fullscreenToggle.on('touchstart', a => {
that.fullscreen.emit(true);
});
});
this.created.emit(player);
}
}
ngOnDestroy() {
console.log('destroyed');
videojs(this.element.nativeElement).dispose();
}
}
UPDATE
After a lot of testing scenarios, I solved this issue with removing "let videojs = require('videojs');" and adding this custom typings definition:
interface VideoJSStatic {
(id: any, options?: any, ready?: () => void): any;
}
declare var videojs:VideoJSStatic;
But I'm looking to know conceptually, what was the reason of this behavior?