4

I have an angular Universal application(server-side rendering). I am using IntersectionObserver for lazy loading images and it is working fine. Although it is giving me this error on server-side logs (pm2 server-error.log).

ERROR ReferenceError: IntersectionObserver is not defined
    at LazyLoadDirective.lazyLoadImage (/home/ubuntu/dist/server/main.js:13160:21)
    at LazyLoadDirective.ngAfterViewInit (/home/ubuntu/dist/server/main.js:13154:33)
    at callProviderLifecycles (/home/ubuntu/dist/server/main.js:52384:18)
    at callElementProvidersLifecycles (/home/ubuntu/dist/server/main.js:52349:13)
    at callLifecycleHooksChildrenFirst (/home/ubuntu/dist/server/main.js:52331:29)
    at checkAndUpdateView (/home/ubuntu/dist/server/main.js:63214:5)
    at callViewAction (/home/ubuntu/dist/server/main.js:63570:21)
    at execComponentViewsAction (/home/ubuntu/dist/server/main.js:63498:13)
    at checkAndUpdateView (/home/ubuntu/dist/server/main.js:63211:5)
    at callViewAction (/home/ubuntu/dist/server/main.js:63570:21)

which I understand is because IntersectionObserver is client side thing since it operates on DOM elements.

But It is kind of annoying to see the above error on the server side so I wanted to correct the issue for that I took the help of isPlateformBrowser function by injecting PLATEFORM_ID into my lazyload directive. It is still working fine for me and I am not seeing any server-side error logs for this.

This is my LazyLoadDirective code

export class LazyLoadDirective implements AfterViewInit{

    @HostBinding('attr.src') srcAtr = null;
    @Input() src: string;

    constructor(private el: ElementRef, @Inject(PLATFORM_ID) private plateformId : Object) {}

    //putting check for isplateformbrowser.
    ngAfterViewInit(){
        if(isPlatformBrowser(this.plateformId)){
        this.canLazyLoad ? this.lazyLoadImage() : this.loadImage();
        }
    }

    private canLazyLoad(){
        return window && 'IntersectionObserver' in window;
    }

    private lazyLoadImage(){
        const obs = new IntersectionObserver(entries =>{
            entries.forEach(({ isIntersecting })=>{
                console.log("intersecting value isIntersecting",isIntersecting);
                if(isIntersecting){
                    this.loadImage();
                    obs.unobserve(this.el.nativeElement);
                }

            });
        });

        obs.observe(this.el.nativeElement);
    }

    private loadImage(){
        this.srcAtr = this.src;
    }
}

Since this is something new for me, It would be really helpful for me if someone could suggest a better solution for this problem, Also I have seen some post on a different platform that IntersectionObserver is not reliable. Please help me understand the scenarios where this could cause trouble, any link to a blog post or any kind of help is enough for me. Thank you.

Ayush Chaurasia
  • 345
  • 4
  • 9
  • Why do you need a better solution? I think that's one is good enough. As for IntersectionObserver, it should work pretty much everywhere (https://caniuse.com/#search=IntersectionObserver) – David Dec 12 '19 at 09:34
  • Okay, Thank you for the response and for the link, David, Although This is being used in my code and It is working properly(Since I had a question about the reliability). – Ayush Chaurasia Mar 31 '20 at 12:11

1 Answers1

0

Awesome!!! I added a '@HostBinding('class') elementVisibilityClass: string' onto that directive to add a CSS class on the targeted element depending on the visibility status.

@HostBinding('class') elementVisibilityClass: string;
...
private _callback = (entries: any) => {
    entries.forEach((entry: any) => {
      this.elementVisibilityClass = entry.isIntersecting ? 'visible' : 'hidden';
    });
}