Image Slider with Dynamic Collection - Display Images Only When Fully Loaded

Hello WeWeb Community,

I’m currently working on a project where I’m using the built-in “Image Slider” component as an element of a dynamic collection in a catalog. The images for all offers are loaded from the database into this slider. My goal is to ensure that these images are only displayed when they are fully loaded in the browser, so users don’t see them loading piece by piece.

Here’s what I’ve tried so far:

Using JavaScript to Check Image Load Status : I attempted to write a custom JS function to check if the images are fully loaded before displaying them. However, it seems like the function always returns false, and the images are not being displayed correctly.
Conditional Display Based on Variable : I created a variable imagesLoaded (boolean) and tried to use it in the condition settings of the image slider block. The idea was to set this variable to true once the images are fully loaded, but it doesn’t seem to work as expected.
Here’s the code snippet I used:

function checkImageLoad() {
return new Promise((resolve) => {
const img = document.querySelector(‘#images_slider img’); // Using id ‘images_slider’ and tag ‘img’

    if (!img) {
        console.log('Image not found');
        resolve(false); // If image not found, return false
        return;
    }

    console.log('Image found');

    if (img.complete && img.naturalWidth !== 0) {
        console.log('Image already loaded');
        resolve(true); // Image already loaded, return true
        return;
    }

    let loaded = false;

    img.onload = () => {
        loaded = true;
        console.log('Image loaded');
        resolve(true); // Image loaded, return true
    };

    img.onerror = () => {
        console.log('Error loading image');
        resolve(false); // Error loading, return false
    };

    setTimeout(() => {
        if (!loaded) {
            console.log('Image not yet loaded');
            resolve(false); // Image not yet loaded, return false
        }
    }, 3000);
});

}

// Example usage:
checkImageLoad().then(result => {
we.setVariable(‘imagesLoaded’, result);
});

Despite my efforts, the images are still not displaying correctly. They either don’t show up at all or continue to load piece by piece.

Could anyone provide guidance on how to properly implement this functionality? Any advice or alternative solutions would be greatly appreciated!

Thank you in advance for your help!

Hello @alnkde,

Did you create a collection for your images?

If yes, you could bind the property “conditional rendering” of your slider to: yourCollection.isFetched && not(yourCollection.isFetching)

With that, I think that you will have the result you want

Thank you for your suggestion! I appreciate the advice. Yes, I did create a collection for my images and I have already implemented the “conditional rendering” property of my slider using yourCollection.isFetched && not(yourCollection.isFetching). This approach works well for ensuring that the collection is fully fetched before displaying the slider.

However, the issue I’m facing is slightly different. The problem is not with the collection fetching process; I have a skeleton loader in place to handle that. The challenge lies in the actual rendering of the images in the browser. Sometimes, the images within their containers load slowly and appear piece by piece. This partial loading is visible to the user, which is not the desired behavior.

What I want to achieve is to display the images only when they are fully rendered and loaded in the container. In other words, I want the image to appear all at once, as if it’s flashing directly onto the screen, rather than seeing it load incrementally. If an image isn’t fully rendered and physically loaded into its container, I don’t want it to be shown at all until it is completely ready.

So, while the collection fetching condition helps ensure that the data is ready, it doesn’t address the issue of the images themselves being partially loaded in the browser. I need a solution that ensures the images are fully loaded and rendered before they are displayed to the user.

Do you have any suggestions on how to achieve this? Any additional tips or alternative approaches would be greatly appreciated!

Thank you again for your help!

Hello,

Facing same issue, here :slight_smile:

This is working for me, only when using an image inside a component. Try playing with the following JS:

  1. Create a workflow in the image element with the “On Mounted” trigger.
  2. Add a small delay 20-50ms to ensure the action fires
  3. Add a custom JS action to the workflow.
  4. Add the following code:

// Get the img element from the current instance
const img = context.thisInstance.querySelector(“img”);

// Add load event listener that runs the function when the image loads
img.addEventListener(‘load’, () => {
// Change a variable to true or whatever you’d like to do when the image loads
variables[‘variableid’] = true;
});

return true;

//

Images in the main element tree are not being able to be referenced correctly (haven’t been able to do so, even by assigning an id to the image) so it’s important to use this in an image that is inside of a component.

Edit: I was able to reference images in the main element tree with the same code after some experimenting. The way I did it was doing the same as above, but for some reason I had to add another native Weweb “change variable value” action to the workflow after the custom JS action. I ran this workflow and this second action changed the variable value once. I then deleted this second action and left the custom JS. Now for some reason the original JS action works?? No other testing was made. Odd, but at least it’s a fix.

this is an interesting approach, thank you!

i’m using your approach in a list with repeated items. each item is a saved component. i’m using the common weweb Image component and binding the image URL to its source, no backend loading.

after some debugging of the error message: “Invalid left-hand side in assignment” here is a more robust version of the code, to set the private variable of the component i use the updateVariable() function:

// Get the img element from the current instance
const img = context.thisInstance.querySelector("img");

/*
complete Property
- Returns true if the image has fully loaded or failed to load.
- Returns false if the image is still loading.
naturalWidth Property
- If naturalWidth is 0, the image failed to load.
Event Listeners
- "load" fires when the image successfully loads.
- "error" fires if the image fails to load.
*/

// If image completed but errored (e.g. 404 url)
if (img.complete && img.naturalWidth !== 0)
     context.component.methods.updateVariable(/* imageHasLoaded */ '1fe24dca-your-var-id', true);
else // Add load event listener that runs the function when the image loads
img.addEventListener("load", () => {
     context.component.methods.updateVariable(/* imageHasLoaded */ '1fe24dca-your-var-id', true);
});

return true;

hope it helps others

1 Like