tjoskar / ng-lazyload-image

🖼 A small library for lazy loading images for Angular apps with zero dependencies
https://naughty-bose-ec1cfc.netlify.com
MIT License
762 stars 142 forks source link

Set global window replacement #323

Closed joshhills closed 6 years ago

joshhills commented 6 years ago

This is a feature request - I'm happy to try to contribute but I'm not entirely sure where best to put it.

There have been a few issues you've answered already concerning the idea that somebody mightn't be using the window as a scroll but rather some sort of custom nested container dependent on their framework.

I'm using a div in Angular2 that is smaller than the window and has overflow-y: scroll; ergo, the events do not bubble up. The images inside the div are furthermore within child components. I know you can pass scrollTarget, however that would mean that for every image in my application, its parent component would have to go get a reference to that one scroll container to pass in. Creating a service to return a reference to that one component also seems obtuse.

I've temporarily replaced line 49 in the directive script with: scrollObservable = scroll_listener_1.getScrollListener(_this.scrollTarget || document.getElementById("MY-COMPONENT")); - awful, I know. I think it would be better to be able to tell the plugin globally to use a different element to the window as a fallback.

Thoughts? 😄

tjoskar commented 6 years ago

I really see a use case for this. Not only for scrollTarget but also to make it possible to create a custom isVisible (to use some other algorithm, eg. IntersectionObserver), loadImage (to create custom http requests) and so on.

I guess the best way to support this is to create a fromRoot-function where we can inject and set static configurations.

I will accept a PR if you are up to the task @joshhills and I will help you out in any way I can.

joshhills commented 6 years ago

Ah, I had always wondered what forRoot did exactly. I'll see if I can spare some time over the next week to get a configuration passed in to just set the scrollTarget fallback, and if that works then you could perhaps expand on that to more easily deal with the other feature requests people are leaving that are similar in nature?

rivernews commented 6 years ago

Update It turns out that fullscreen causes the scroll listener be taken away from window. When I change <mat-sidenav-content fullscreen ... to <mat-sidenav-content ..., the window now fires scroll events and lazy load image is now working!


Original

Hi, I'm running into the same problem. I use Angular Material 2 and had a mat-sidenav-content containing the whole website contents in the root component app.component.html.

When I do <mat-sidenav-content (scroll)="...my debug function here...">, I can see the scroll event is fired and printed out. But not the window - listening to scroll event on window doesn't work for me in this case. This causes ng-lazyload-image not loading the image.

I wonder if there is an option to opt out the trigger-by-scrolling for deciding the timing of loading image. But then this might no longer be "lazy" loading images. Currently I'm considering some alternative solutions like load in images one by one at a time instead of concurrently, to mitigate the lag effect on the web page. I understand this is out of scope of ng-lazyload-image though. But using some libraries like Angular Material 2 along with mat-sidenav-content seems like a common use case, so I really hope is there some work around on this.

tjoskar commented 6 years ago

Hi @joshhills,

This should be possible in 2.1.0.

If you fist define getObservable

import { fromEvent } from 'rxjs';

function getObservable() {
  return fromEvent(document.getElementById("MY-COMPONENT"), 'scroll');
}

And then give it to LazyLoadImageModule in NgModule.

@NgModule({
  declarations: [ AppComponent ],
  imports: [
    BrowserModule,
    LazyLoadImageModule.forRoot({ getObservable })
  ],
  bootstrap: [ AppComponent ]
})

Or even better. Using intersectionObserver so you don't need to listen for scroll events.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { LazyLoadImageModule, intersectionObserverPreset } from 'ng-lazyload-image';
import { AppComponent } from './app.component';

@NgModule({
    declarations: [ AppComponent ],
    imports: [
      BrowserModule,
      LazyLoadImageModule.forRoot({
        preset: intersectionObserverPreset
      })
    ],
    bootstrap: [ AppComponent ]
})
export class MyAppModule {}

Let me know if you run into any problems.