8

I have an HTML5 <video> element in an Angular2 component. I need access to it in order to check the duration before allowing the user to share it to Twitter.

Is there any way through model binding, or direct access to the DOM, that I can get this information in the component's backing class?

I've tried binding it using ng-model, like this in the component's template:

<video controls width="250" [(ng-model)]="videoElement">
    <source [src]="video" type="video/mp4" />
</video>

and in the component's class (TypeScript):

videoElement: HTMLVideoElement;

That gives me this error: EXCEPTION: No value accessor for '' in [null]

I was able to access it by just giving the video element an id and using document.getElementById("videoElementId") but it seems like there must be a better way.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
Sam
  • 4,994
  • 4
  • 30
  • 37
  • I can use document.getElementById, but it is not allowed to use function like: videoElement.play() or videoElement.pause(). Do you know how to do with it if I want to play/pause a video? – Ng2-Fun Mar 04 '16 at 15:01
  • 1
    @J.Fun I just tried in the console and both of those functions work for me using document.getElementById("videoid").play(); -- What do you mean it's not allowed? I would suggest asking a new question if you're having issues. – Sam Mar 04 '16 at 15:45
  • I mean, it reminds me an error: TS2339: Property 'play' does not exist on type 'HTMLElement' when compiling typescript in PhpStorm. Although it actually works in my browser. The error message is still very annoying, I don't know how to get rid of it. – Ng2-Fun Mar 04 '16 at 16:33
  • 2
    I think you need to cast it to the correct type (HTMLVideoElement). Something like this: document.getElementById("videoid") The error occurs because it's treating the element as a generic HTMLElement. JavaScript doesn't care, but TS has extra checks to ensure type safety – Sam Mar 04 '16 at 16:47

2 Answers2

13

You can inject the ElementRef and then access the element like

element.nativeElement.shadowRoot.querySelector('video').duration;
// with encapsulation: ViewEncapsulation.Native

and with other view encapsulation modes probably

element.nativeElement.querySelector('video').duration;

(not yet tried myself though).


This should work as well

<video (durationchange)="durationChangeEventHandler($event)"></video>

and then access it using $event.target


Using a directive (example in Dart code)

@Directive(selector: 'video')
class VideoModel {
  ElementRef _element;
  VideoModel(this._element) {
    VideoElement video = _element.nativeElement as VideoElement;
    video.onDurationChange.listen((e) => duration = video.duration);
  }

  num duration;
}

In your component add

@Component(
    selector: 'my-component',
    viewProviders: const [VideoModel], 
    directives: const [VideoModel],
    templateUrl: 'my_component.html') 
class MyComponent {
    @ViewChild(VideoModel) 
    VideoModel video;
}

now you can access the duration with video.duration

Sam
  • 4,994
  • 4
  • 30
  • 37
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 2
    Both methods worked, thanks! Minor edit though, it would be $event.target in your example – Sam Dec 11 '15 at 18:06
-2
<html ng-app="VideoLink">    

<body ng-controller="linkvideo">
    <video controls>
        <source src={{video}} type="video.mp4">
    </video>
</body>
</html>

in the controller file

var videolink=angular.module('VideoLink',[]);

    videolink.controller('linkvideo',function($scope){      
    $scope.video={'name':'https://www.youtube.com/watch?v=R7GLYhJ51uo'}
    });

Try it may be it will helpful for you

Grayfoox
  • 47
  • 10
Pankaj Gupta
  • 378
  • 2
  • 10