Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome (Android) video autoplay inside Angular 2+ component

What does not work:

If I put a video tag with "autoplay" (see below) into the template of an Angular 2+ component with the goal of autoplaying on mobile:

<video muted autoplay>
    <source src="path/to/video.mp4" type="video/mp4" />
</video>

What does work:

  • Moving it to the index.html (outside of the Angular component)
  • Appending it to the body from within the component:

    window.addEventListener('load', () => {
        document.body.innerHTML += "<video autoplay muted loop>\n" +
                                   "    <source src=\"path/to/video.mp4\" type=\"video/mp4\" />\n" +
                                   "</video>";
    });
    
  • Including the video in the component's template, enabling the "user controls", and manually touching the play button on the video (i.e. no autoplay)

Theories:

I don't think it's an issue of an invalid path to the video, since I'm able to manually click the "play" button.

According to here and here, autoplay on mobile should be allowed if (1) the video is muted, and (2) the video is "visible". I've read that "visible" in this context is more or less defined to mean "attached to DOM" and not "display: none" in at least a couple of places.

My best theory is that Angular 2+ is sticking the component in some kind of "Shadow DOM" (or similar) that's resulting in mobile Chrome not thinking that it's visible. I tried setting the component to encapsulation: ViewEncapsulation.None to see if that made a difference, but same result.

Additionally, if I try to set an event listener against the "loaded" or "canplaythrough" events and manually call videoElement.play(), then I get: DOMException: play() can only be initiated by a user gesture. If I make the same function call in the devtools console (tethering to mobile device via USB), then it does play.

Final thoughts:

It seems that Angular is likely what's getting in my way. Is there any known Angular setting or workaround I can leverage to get a video to autoplay within an Angular 2+ component on Android Chrome? Thanks for any help.

(p.s.: there's like a million questions on S.O. and elsewhere about autoplaying video on mobile Chrome, but none of them seem to address the issue of doing it within an Angular component or similar)

like image 494
Adam T. Doyle Avatar asked Feb 18 '18 21:02

Adam T. Doyle


4 Answers

I was searching for this issue a lot and I put the muted attribute like this:

[muted]="true" rather than just muted

and now it works

<video [muted]="true" autoplay>
    <source src="path/to/video.mp4" type="video/mp4" />
</video>

Chrome has a policy to not let videos autoplay if the user has not first interacted with the page however if its a muted video chrome allows it. The problem here is that for some reason muted value goes as false when you just put muted in angular.

like image 164
Dilshan Liyanage Avatar answered Nov 18 '22 09:11

Dilshan Liyanage


I needed to use both onloadedmetadata and oncanplay to fix in angular 6

<video id="bg-video" loop muted autoplay oncanplay="this.play()" onloadedmetadata="this.muted = true">
    <source src="video.mp4" type="video/mp4">
</video>
like image 41
tommybananas Avatar answered Nov 18 '22 09:11

tommybananas


Similar issue with Angular 6 and Chrome 70.

In fact, the muted attribute in the HTML seems to be ignored by Chrome when the video is added by Angular. The resulting DOM element has a 'muted' property set to 'false'. Not sure if it is an Angular or a Chrome bug.

You need to set it manually to true to make the autoplay work.

I ended up with a directive :

@Directive({selector: '[my-autoplay]' })
export class AutoplayVideoDirective implements OnInit {

  constructor(public element: ElementRef) { }

  public ngOnInit(): void {
    let vid = this.element.nativeElement;
    vid.muted = true;
    vid.play();
  }
}

and the HTML :

<video loop muted autoplay my-autoplay>
like image 33
Etienne Coumont Avatar answered Nov 18 '22 09:11

Etienne Coumont


Had a similar issue with Chrome 66 (OSX High Sierra) not autoplaying a muted video in a Mat Dialog being opened by its parent on init. Solved it by adding *ngIf="true" to the video element:

<video *ngIf="true" autoplay muted onloadedmetadata="this.muted = true" controls>
    <source src="myVid.mp4" type="video/mp4">
    <p>Your browser does not support the video element.</p>
</video>
like image 3
dalexisv83 Avatar answered Nov 18 '22 11:11

dalexisv83