Reputation: 617
I'm executing a script after the page header image loads:
objImg = new Image();
objImg.src = '/images/header.jpg';
objImg.onload = function() {
$('#myDiv').fadeIn(500);
}
This works great. However on one of the pages I need it to execute after four images are loaded instead of just one. Is there a way to modify this to have it be an array instead of just one image?
Upvotes: 2
Views: 355
Reputation: 34127
I would use something like this.
Use the same approach in your question..
For the array of images, give a class say image-wait-for-load
to the img
tag
Now find how many images are there in you page to be waited.
var waitImageCount = $('.image-wait-for-load').length;
Code to check if all images are loaded.
$(document /* or what ever */).on('load', '.image-wait-for-load', function() {
waitImageCount--; // decrease the counter
if(waitImageCount === 0) {
// all images are loaded.
// Do what ever you like
}
});
Please note that this untested code, but I hope something like this should work.
Upvotes: 2
Reputation: 43950
The demo below uses an async
function and await
keyword so that a Promise controls the asynchronous interaction between client (you) and a live test server at the given endpoint (first parameter). A selector (second optional parameter) of a DOM element is passed to specify where to render images (default is "body"
if not defined).
fetchImages("https://sub.domain.tld/path/to/json", "tagName#id.className[attribute]"/*or "body"*/)
fetch()
is an asynchronous function that guarantees a response or rejection of requested data via the await
keyword. The .json()
method (also preceded by await
) retrieves the JSON.
const response = await fetch(`https://api.myjson.com/bins/19fk22`);
let imgArray = await response.json();
/* At this point the JSON is stored in a variable called imgArray
imgArray = [
"https://i.ibb.co/hZj77BZ/lena01.jpg",
"https://i.ibb.co/7XxsBr5/lena02.png",
"https://i.ibb.co/X7SCb3w/lena03.png"
]
*/
Next, the JSON array (aka imgArray
) is ran through the array method .forEach((src, idx) => {...
. Each url (src
first parameter) within imgArray
is processed. The following is a step-by-step breakdown of the first image url being processed (Note how the second parameter idx
is used in step #3):
Reference the DOM element that the images will be placed within
const node = document.querySelector('.gallery')
// <header class="gallery">|<= images will be inserted here =>|</header>
Extract the file name of image with .split()
let name = src.split('/')
// ['https:', 'i.ibb.co', 'hZj77BZ', 'lena01.jpg']
.pop()
// 'lena01.jpg'
.split('.')
// ['lena01', 'jpg']
.shift();
// 'lena01'
Assign a template literal of an htmlString
to a variable (let html
) and then interpolate ${values}
and/or ${expressions}
let html = `
<figure style="animation: ${3 * (idx+1)}s fadeIn">`
/* <figure style="animation: 3s fadeIn">
Each iteration is assigned an increased CSS animation-duration value.
The first image fades in for 3sec, the second image fades in for 6sec, third 9sec, etc.
The actual code for the animation is in the CSS.
*/
`<img src="${src}">`
// <img src="https://i.ibb.co/hZj77BZ/lena01.jpg">
`<figcaption>${name}</figcaption>`
/* <figcaption>LENA01</figcaption>
The name value from step #2 is inserted as a caption and styled by CSS
*/
`</figure>`;
node.insertAdjacentHTML("beforeend", html);
/* .insertAdjacentHTML(position, htmlString) is .innerHTML on steroids
@Param: [Position]: "beforebegin", "afterbegin", "beforeend", or "afterend"
@Param: [htmlString]: strongly suggest that template literals be used instead of literal strings
const endpoint = `https://api.myjson.com/bins/19fk22`;
const fetchImages = async(endpoint, selector = "body") => {
const response = await fetch(endpoint);
let imgArray = await response.json();
imgArray.forEach((src, idx) => {
const node = document.querySelector(selector);
let name = src.split('/').pop().split('.').shift();
let html = `
<figure style="animation: ${3 * (idx+1)}s fadeIn">
<img src="${src}">
<figcaption>${name}</figcaption>
</figure>`;
node.insertAdjacentHTML("beforeend", html);
});
}
fetchImages(endpoint, '.gallery');
.gallery {
display: flex;
justify-content: center;
width: 96%;
margin: 10px auto;
padding: 5px;
background: rgb(138, 56, 201);
}
figure {
width: 50vw;
margin: 10px 2.5px 5px;
}
figcaption {
font: 700 small-caps 3vw/1 Arial;
color: gold;
text-align: center;
}
img {
width: 100%;
height: auto;
}
@keyframes fadeIn {
from {
opacity: 0;
}
50% {
opacity: 0.66;
}
to {
opacity: 1;
}
}
<header class='gallery'></header>
Upvotes: 0
Reputation: 1429
It could be done using Promises like here. Or simply loop while storing their sources in a parallel array and use a callback function when all images are preloaded. The parallel array, could be useful during loading errors too so we could use it to display only preloaded and valid images.
A more sophisticated approach would add a function to test image availability before even preloading it using XMLHttpRequest(); or a ajax.
Notice that I'm using a fake picture here to test loading failure.
var pix = new Array('https://image.shutterstock.com/image-photo/colorful-hot-air-balloons-flying-260nw-1033306540.jpg','https://images.fineartamerica.com/images-medium-large-5/hot-air-balloons-over-hay-bales-sunset-landscape-matthew-gibson.jpg','https://iso.500px.com/wp-content/uploads/2014/07/big-one.jpg','https://some.thing/undefined.jpg','https://cdn-media.rtl.fr/cache/4gx11M-ZCLtBdzqGMR2TWA/880v587-0/online/image/2019/1212/7799676803_l-enfant-de-the-mandalorian-est-la-star-de-la-galaxie.jpg');
var total = pix.length;
var ctr = 0;
var cache=[];
for(var i=0; i<total; i++){
var img = new Image();
img.src = pix[i];
//We push it to the cached elements list
cache.push(img);
img.onload = function(){
console.log('Pic loaded!');
ctr++;
//When all are loaded
if(ctr == total){
console.log('All done ;) ');
//We append them to the targeted div
WellDone();
}
}
img.onerror = function(){
//Because we didn't test the picture loading before adding it, we have to remove the failing image from the array
cache.splice(i, 1);
ctr++;
if(ctr == total){
console.log('All done ;) ');
//We append them to the targeted div
WellDone();
}
}
}
function WellDone(){
//finally here things could run in a sequence!
for (var i = 0; i < cache.length; i++) {
$('#myDiv').append(cache[i]);
}
cache=[];
$('#myDiv').fadeIn(500);
}
#myDiv{
display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="myDiv"></div>
Upvotes: 1