Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Images are not loaded after switching between routes #438

Closed
zZeepo opened this issue Feb 22, 2020 · 14 comments
Closed

Images are not loaded after switching between routes #438

zZeepo opened this issue Feb 22, 2020 · 14 comments

Comments

@zZeepo
Copy link

zZeepo commented Feb 22, 2020

Hey,
thanks for this repo.
Really useful and generally well working!

I only ran into one problem in my application:
The problem occurs after switching to a new route in my application.
After the initial load of the app everything loads as expected, but for all following navigations the images are not loading in the newly rendered page. Once I scroll on the new route all images load correctly. This problem only occurs when using preset: scrollPreset. If I switch to the IntersectionObserver, everything works as expected (except from some known IntersectionObserver browser issues).

I did a bit of debugging and the following seems to be happening:
The isVisible() check runs as soon as Angular appends and initialized the new content of the new route at the end of the page. While this is happening the content of the previous page is still part in the DOM, occupying the viewport. Because of this, the isVisible() will never be true and no images are loaded.
Once the new route is fully loaded and the components of the previous route are removed, the isVisible() requires a scroll event to be executed again.

My application is running Angular 9.0.0.
Might be related to this: #433

For now I'm working with this workaround, but I'm not happy with it.

ngAfterViewChecked () {
  window.dispatchEvent(new CustomEvent('scroll', {}))
}

I use your directive inside of one broadly used component in my application.
Inside of this component I fire a custom fake scroll event to trigger another visibility check once everything is ready.

Let me know if I can assist in solving this.

@tjoskar
Copy link
Owner

tjoskar commented Feb 22, 2020

Hi @zZeepo, thanks for sharing your issue.

First of all I have some questions:

  1. When you say: If I switch to the IntersectionObserver, everything works as expected (except from some known IntersectionObserver browser issues).. What issues are you talking about? I'm just curious, it would be nice to know what people are running into 😃
  2. Maybe same question as above but what is holding you back from using IntersectionObserver?

Regarding your issue, you are probably right regarding that the content might not be removed before the ng-lazyload-image has been instantiated on the new page and that the position on the image is not accurate. I have not experienced this is in earlier version of Angular but I will try to create an example in Angular 9 to see if I can understand the issue better.

@zZeepo
Copy link
Author

zZeepo commented Feb 23, 2020

Hey @tjoskar,
thanks for the reply.

  1. To be fair most of my troubles I encountered a while ago, when I was first experimenting with the IntersectionObserver. Some of the issues might already be resolved.
    But those were mainly the two I faced:
  • Some elements were not detected when the parent was using the Flexbox layout.
    Back then, I found a StackOverflow question with a codepen to reproduce this issue. I search for it to show it to you, but unfortunately I was not able to find it anymore.
  • Contents with a height or width of 0 pixels never intersect with the viewport.
    So I had to make sure all elements have a sizes, even before they are loaded. For most of my lazyloaded elements I try to apply the final dimensions even before they are loaded to avoid changes to the layout on load, but for some I was facing issues with this. (Most cases could be avoided with min-height: 1px; min-width: 1px tho. w3c/io/issues/69
  1. I made the choice not to use the IntersectionObserver when I first implemented a custom lazyload component for my application. Back then I was facing the issues mentioned above and the IntersectionObserver seemed a bit experimental to me. When switching from my to your implementation, I kinda just sticked with this choice tbh. I had a some tests with the IntersectionObserver configuration at first and a few contents where not loading (I think those where zero-dimension related). The scrollPreset worked right out of the box with my application.

After trying around for a bit now, I think I will give the IntersectionObserver another chance tho. It seems to have become quite a powerful API in the meantime. I switched my configuration to it now and will see if any issues pop up.

Regarding the issue:
Let me know if you need any more information. I can try doing more tests using the scrollPreset.

@tjoskar
Copy link
Owner

tjoskar commented Feb 24, 2020

Interesting! Thanks for sharing, I really appreciate it!

I just tried to change to the scrollPreset in the example app which is running in Angular 9 and it seems to be working fine to navigate between views/routes.

Just so you know, in version 7.1.0 there is a new debug property which will output some debug info while loading the images. It would be interesting if you could add it to see if you are getting any events after the navigation.

@tjoskar
Copy link
Owner

tjoskar commented Feb 24, 2020

Now when I'm thinking about it, I think it can be hard to know the state of every event (know if the dom has been updated or not when we got the first event).

@zZeepo
Copy link
Author

zZeepo commented Feb 26, 2020

hmm... I installed your example application and the error actually does not show up there for me as well. I'm now trying to find the difference between your and my application.

The routing seems to behave different:
For testing I put a debugger statement in your isVisible$2 function, so I can check the state of the app during the initial isVisible call. In your application the previous page is fully removed from the dom, while in mine, the page consist of the previous page plus the new page at the end.

I'll do further investigations in the next days, but I just wanted to give you an update so far.

Regarding the debugging:
Those are the events logged on the initial pageload

{reason: "setup"}
{reason: "observer-emit", data: ""}
{reason: "start-loading"}
{reason: "mount-image"}
{reason: "loading-succeeded"}
{reason: "finally"}

The following navigation then only have these events logged:

{reason: "setup"}
{reason: "observer-emit", data: ""}

The rest only gets logged after I scroll.

@tjoskar
Copy link
Owner

tjoskar commented Feb 27, 2020

You are getting the observer-emit-event right before isVisible and you seem to get the same result when you added the debugger statement.

The main issue seems to be (as you already pointed out) the fact that the old page is still in the DOM after a route change.

What version of Angular are you using?

@tjoskar
Copy link
Owner

tjoskar commented Feb 28, 2020

@zZeepo is there any chance that I can get access to your codebase or if you have been able to create a simple app where you reproduce the issue?

@zZeepo
Copy link
Author

zZeepo commented Mar 7, 2020

Hey
I've been away for a few days with limited access to an internet connection.
Now I'm back tho and ready to answer your questions.

What version of Angular are you using?

My application was running with 9.0.0.
Today I updated to 9.0.5, but the error is still here.

is there any chance that I can get access to ...

Unfortunately the repository is private and I can not share the code.
I'm still trying to reproduce the error in an example repository to be able to share a reproduction.

So far I've tried the following with no success:

  • using the directive in a nested route
  • using the directive inside a subcomponent on the page
  • using the directive inside a lazyloaded module
  • using different initialNavigation options

Will try to figure out the difference between my and the example app and keep you up to date.

@zZeepo
Copy link
Author

zZeepo commented Mar 8, 2020

Ok, finally!
After taking apart my app one by one to pinpoint the error, I think I have a way to reproduce it in your example app. The rendering order on route changes seems to change if you import the BrowserAnimationsModule. This new order seems to conflict with the scrollPreset mechanic.
To reproduce the error you just have to change the following lines in your example app and add the imports accordingly.

src/app/app.module.ts

- LazyLoadImageModule.forRoot(intersectionObserverPreset)
+ LazyLoadImageModule.forRoot({
+   preset: scrollPreset,
+ }),
+ BrowserAnimationsModule,

@tjoskar
Copy link
Owner

tjoskar commented Mar 13, 2020

Thank you so much for the finding @zZeepo!
It is like you were saying; the animation makes the elements from the previous page be kept above the new elements. The only solution I see is to emit an event when the old elements are removed. Like you were doing:

ngAfterViewChecked() {
  window.dispatchEvent(new CustomEvent('scroll', {}))
  // or somthing like:
  this.mySubject.emit({});
}

It might be possible to add this extra event emitter in ng-lazyload-image and maybe control it by a flag:

LazyLoadImageModule.forRoot({
  preset: scrollPreset,
  extraCheck: ['ngAfterViewChecked']
})

But it will add some complexity and I'm not sure it is worth it. You said you should give IntersectionObserver another chance. Did you do it? Do you still want to use the scroll-listener?

@zZeepo
Copy link
Author

zZeepo commented Mar 13, 2020

But it will add some complexity and I'm not sure it is worth it. You said you should give IntersectionObserver another chance. Did you do it? Do you still want to use the scroll-listener?

Yes I did.
So far I'm really happy with the results.
If no issues occur in the near future I plan on keeping the IntersectionObserver preset.

Since we have identified the source and figured out a decent workaround for the issue:
Should we mark this issue as closed? I'll leave the question wether you want to implement an extra event emitter up to you. I guess, it would be enough to mention it as a known issue tho.

@tjoskar
Copy link
Owner

tjoskar commented Mar 13, 2020

Thank you so much for the investigation @zZeepo!
I will add this issue to the readme as a known issue (and keep this issue open untill then).

@zZeepo
Copy link
Author

zZeepo commented Mar 13, 2020

No problem! I'm happily using this repo in my project.
So I appreciate the work you put in developing this and I'm glad I could assist.

tjoskar pushed a commit that referenced this issue Mar 20, 2020
@tjoskar
Copy link
Owner

tjoskar commented Mar 20, 2020

I added a link to this issue in the readme. Thanks once again.

@tjoskar tjoskar closed this as completed Mar 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants