w3c/IntersectionObserver

when trying to make the application serve-side rendered using angular universal, intersection observer's disconnect method is not defined.

Closed this issue · 10 comments

Used intersection observer for infinite scroll in angular 8.
`import { Component, OnInit, Input, Output, EventEmitter, ElementRef, ViewChild, OnDestroy } from '@angular/core';

@component({
selector: 'app-infinite-scroll',
template: <ng-content></ng-content><div #anchor></div>,
styleUrls: ['./infinite-scroll.component.scss']
})
export class InfiniteScrollComponent implements OnInit, OnDestroy {

@input() options = {};
@output() scrolled = new EventEmitter();
@ViewChild('anchor', {static: true}) anchor: ElementRef;

private observer: IntersectionObserver;

constructor(private host: ElementRef) { }

get element() {
return this.host.nativeElement;
}

ngOnInit() {
const options = {
root: null,
...this.options
};

this.observer = new IntersectionObserver(([entry]) => {
  return entry.isIntersecting && this.scrolled.emit();
}, options);

this.observer.observe(this.anchor.nativeElement);

}

ngOnDestroy() {
this.observer.disconnect();
}

}
`
when i do an ng serve, the component works fine.
when i try to serve side render the app using angular universal I get the following error
ERROR ReferenceError: IntersectionObserver is not defined
and
TypeError: Cannot read property 'disconnect' of undefined
both in server\main.js in the dist folder

Any help is very appreciated. Thank you.

/cc @housseindjirdeh @mgechev

Any idea why the Intersection Observer polyfill wouldn't work in an Angular app using SSR?

@philipwalton , Did you get any chance to look in to this ? If you can suggest a way, i will try to implement and update you. Thanks.

The chances are that the issue is not in the IntersectionObserver polyfill itself, but in the way it's used with Angular Universal.

@koundinyab could you run the code conditionally and use the IntersectionObserver only on the client? Alternatively, could you provide a minimal demo in which we can reproduce the issue?

Hi
Created a repository with sample code
https://github.com/koundinyab/intersection-observer-demo
You can do ng serve to see the output and
npm run build:ssr && npm run serve:ssr
to see the error for universal.
iodemo-error

Please let me know if implementation can be changed to make it work.
Much thanks.

@mgechev Any update please

I am facing the same issue with the disconnect(). I have implemented it in server side rendered React application.
the component works fine when running on development but when I create a production build, it complains about the disconnect().

Following is my implementation
componentDidMount() {
const { src } = this.props;
this.observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
const { isIntersecting } = entry;
if (isIntersecting) {
this.element.src = src;
this.observer = this.observer.disconnect();
}
});
},
{
root: document.querySelector('.swipe'),
threshold: [0, 0.25, 0.5, 0.75, 1],
rootMargin: '10px',
}
);
this.observer.observe(this.element);

render(){
return (<img ref = {(el)=>{this.element = el }}/>)
}

/cc @housseindjirdeh @mgechev

Any idea why the Intersection Observer polyfill wouldn't work in an Angular app using SSR?

In my experience the problem is that at the end the polyfill reference to the window object and on server side we don't have window just global, so It won't find any instance of the IntersectionObserver.

https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js#L880

Any update on this?

When the app is rendered on server side, observer callback cannot be found. Because observer callback is executed by browser. To handle this issue, observer should be created conditional like:

if (typeof window !== 'undefined') {
this.observer = new IntersectionObserver(([entry]) => {
return entry.isIntersecting && this.scrolled.emit();
}, options);

this.observer.observe(this.anchor.nativeElement);

}

When the app is rendered on server side, observer callback cannot be found. Because observer callback is executed by browser.

This is correct. I recommend we close this issue since server-side environments aren't supported by the polyfill.