Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save saber13812002/463ca45d1e60076e8f689c4da9f89dcd to your computer and use it in GitHub Desktop.
Save saber13812002/463ca45d1e60076e8f689c4da9f89dcd to your computer and use it in GitHub Desktop.
Ionic - Auto play/pause videos on scroll.
import { Directive } from '@angular/core';
@Directive({
selector: 'video'
})
export class AutoplayVideoDirective { }
import {AutoplayVideoDirective} from '../../directives/autoplay-video/autoplay-video';
import {Component, ContentChildren, ElementRef, NgZone, OnDestroy, OnInit, QueryList} from '@angular/core';
/*
* Make sure you install the 'intersection-observer' polyfill package from npm, and import it into your app.module.ts
*/
@Component({
selector: 'autoplay-content',
template: `<ng-content></ng-content>`
})
export class AutoplayContentComponent implements OnInit, OnDestroy {
@ContentChildren(
AutoplayVideoDirective,
{ read: ElementRef, descendants: true })
autoPlayVideoRefs: QueryList<AutoplayVideoDirective>;
private intersectionObserver: IntersectionObserver;
private mutationObserver: MutationObserver;
private play: Promise<any>;
constructor(private element: ElementRef,
public ngZone: NgZone) { }
public ngOnInit() {
// we can run this outside the ngZone, no need
// to trigger change detection
this.ngZone.runOutsideAngular(() => {
this.intersectionObserver = this.getIntersectionObserver();
this.mutationObserver = this.getMutationObserver(this.element.nativeElement);
});
}
// clean things ups
public ngOnDestroy() {
if (this.intersectionObserver) {
this.intersectionObserver.disconnect();
}
if (this.mutationObserver) {
this.mutationObserver.disconnect();
}
}
// construct the InterSectionObserver and return it
private getIntersectionObserver() {
return new IntersectionObserver(
// trigger the 'onIntersection' callback on ...
entries => this.onIntersection(entries), {
// ... both 0% and 50% percent of the intersection of the video
threshold: [0, 0.5]
});
}
// construct the MutationObserver and return it
private getMutationObserver(containerElement: HTMLElement) {
let mutationObserver = new MutationObserver(
// execute the onDomChange
() => this.onDomChange()
);
// at the very least, childList, attributes, or characterData
// must be set to true
const config = {
attributes: true,
characterData: true,
childList: true
};
// attach the mutation observer to the container element
// and start observing it
mutationObserver.observe(containerElement, config);
return mutationObserver;
}
private onDomChange() {
// when the DOM changes, loop over each element
// we want to observe for its interection,
// and do observe it
this.autoPlayVideoRefs.forEach((video: ElementRef) => {
this.intersectionObserver.observe(video.nativeElement);
});
}
private onIntersection(entries: IntersectionObserverEntry[]) {
entries.forEach((entry: any) => {
// get the video element
let video = entry.target;
// are we intersecting?
if (!entry.isIntersecting) {
return;
}
// play the video if we passed the threshold
// of 0.5 and store the promise so we can safely
// pause it again
if (entry.intersectionRatio >= 0.5) {
// for demo purposes we use a single video
// this code can easely be
// extended to support multiple videos
if (this.play === undefined) {
this.play = video.play();
}
} else if (entry.intersectionRatio < 0.5) {
// no need to pause something if it didn't start
// playing yet.
if (this.play !== undefined) {
// wait for the promise to resolve,
// then pause the video
this.play.then(() => {
video.pause();
this.play = undefined;
});
}
}
});
}
}
<ion-content>
<!--This is the important bit. You have to wrap your cards with the autoplay-content.component-->
<autoplay-content>
<ion-card *ngFor="let card of cards"
no-padding>
<ion-item>
<ion-avatar item-start>
<img [src]="card.avatarSrc">
</ion-avatar>
<h2>{{ card.name }}</h2>
<p>{{ card.location }}</p>
</ion-item>
<img *ngIf="!card.hasVideo"
[src]="card.src" />
<video *ngIf="card.hasVideo"
playsinline [muted]="true" loop preload="auto">
<source [src]="card.src"
type="video/mp4">
</video>
<ion-card-content>
<p>
Nullam sed tortor ex. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam
dapibus, diam sit amet cursus pellentesque, dolor odio faucibus justo, non ornare ipsum nisl ut sem.
</p>
</ion-card-content>
<ion-row class="comment">
<ion-col>
<strong>
Sarah
</strong> quisque nibh purus, gravida eget arcu blandit? Etiam eros eros, volutpat vitae velit id!
</ion-col>
</ion-row>
<ion-row class="comment">
<ion-col>
<strong>
Marty
</strong> cras a elit eu quam consectetur pretium ... etiam eros eros, volutpat vitae velit id!
</ion-col>
</ion-row>
<ion-row>
<ion-col col-auto>
<button ion-button
color="dark"
clear
small>
<ion-icon name="heart"></ion-icon>
</button>
</ion-col>
<ion-col col-auto>
<button ion-button
color="dark"
clear
small>
<ion-icon name="text"></ion-icon>
</button>
</ion-col>
<ion-col col-auto>
<button ion-button
color="dark"
clear
small>
<ion-icon name="paper-plane"></ion-icon>
</button>
</ion-col>
<ion-col>
&nbsp;
</ion-col>
<ion-col col-auto>
<button ion-button
color="dark"
clear
small>
<ion-icon name="bookmark"></ion-icon>
</button>
</ion-col>
</ion-row>
</ion-card>
</autoplay-content>
</ion-content>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment