I'm trying to do a Fancybox image gallery. I have a function that takes a list of image URLs and appends them to the DOM like so
function handleImageURLs(imageURLs) {
var appendString = "";
//Create an <a> tag for each image URL
for(var i = imageURLs.length - 1; i >= 0; i --) {
appendString += "<a href='"+ imageURLs[i] +"' rel='img_preview'><img src='"+ imageURLs[i] +" />'</a>";
}
//Add the <a> tags containing images to the <body> element
$("body").append(appendString);
//Select the image <a> tags and call Fancybox
$("a[rel='img_preview']").fancybox({
onCleanup: function() {
//do cleanup stuff, remove images, etc.
}
});
}
Everything works fine. The <a> tags get added to the DOM. But Fancybox doesn't open at all. And doesn't throw any errors. Any idea what I'm doing wrong?
Used a combination of this and triggered a click event on the image that I wanted to display.
Related
I am building an image gallery that is populated from a JSON file. Everything works as intended currently, but as of right now there is no pre-loading of content after the initial page load. What I would like to happen is after the "view more" button is clicked I will have some "loading" text show, the batch of images will preload, the "loading" text will disappear, then the images will be added to the page once all items have loaded.
Here is the section of the code that involves the JSON fetch request and the building of elements on the page:
var HTML = '';
var itemsStart = 6; // Starting number of items on page.
var itemsAdd = 9; // Number of items to add to page at a time via button click.
var pItems = document.getElementById('pItems');
var pWrapper = document.getElementById('pItemWrapper');
function addProjects() {
pItems.insertAdjacentHTML('beforeend', HTML);
console.log('BUILD PROJECTS');
}
//Load json
fetch('data/projects.json').then(function (response) {
return response.json();
}).then(function (data){
//Loop through first set of items to load on page.
for (var i = 0; i < itemsStart; i++) {
HTML += '<img src="' + data.projects[i].Image + '" alt=""></img>';
if (i == (itemsStart - 1)) {
addProjects();
}
}
//Load additional items when clicking 'view more'.
document.getElementById('view-more').addEventListener('click', function() {
HTML = '';
for (var i = itemsStart; i < itemsStart + itemsAdd; i++) {
if ((i < data.projects.length)) {
HTML += '<img src="' + data.projects[i].Image + '" alt=""></img>';
}
if (i == ((itemsStart + itemsAdd) - 1) ) {
addProjects();
}
}
itemsStart = itemsStart + itemsAdd;
});
}).catch(function(error) {
console.error('Something went wrong');
});
I'm not using jQuery so I'd like to stick to vanilla js. I don't know what I need to add to my button event listener beyond what I have, I've never tried preloading images like this without using a plugin but I feel like I don't need to load an entire plugin just for this one thing and I'd like to understand how this would work.
EDIT
I feel like I'm almost there, but I still have something wrong. I made some modifications to have each item inside its own container, but instead of that happening I am creating an empty container for each pass of the loop, then the last container gets each image added to it. My code looks like this:
var itemsAdd = 3;
//Load additional items when clicking 'view more'.
document.getElementById('view-more').addEventListener('click', function() {
//The loop will add the next 3 items in the json file per click.
for (var i = itemsStart; i < itemsStart + itemsAdd; i++) {
var placeholder = document.createElement('div');
var src = 'img/portfolio/' + data.projects[i].url;
placeholder.innerHTML= '<div class="img-container">' + data.projects[i].Title + '</div>';
var galleryItem = placeholder.firstChild;
preloadImage(src).then(function (image) {
galleryItem.append(image);
});
pItems.append(galleryItem);
}
itemsStart = itemsStart + itemsAdd;
});
The result I get is this:
Is this because of how the promise works for the preloadImage function?
Generally you would create an image with JavaScript through either document.createElement('img') or the Image() constructor. Both result an in instance of an HTMLImageElement.
With this, you'll have an image that is not connected to the DOM, so it's not visible to you or the user. You can use this element to load the image behind the scenes by setting the image' src property.
Then by listening to the onload event you can determine whenever the image has finished loading. From here you could continue your flow by adding the image to the DOM and, for example, fade it in with animation.
The example below shows this process in the form of a function that returns a Promise. This promise will resolve whenever the load event has been triggered.
const preloadImage = src =>
new Promise(resolve => {
const image = new Image();
const onLoad = () => {
resolve(image);
};
image.addEventListener('load', onLoad, {once: true});
image.src = src;
});
Using it should be like this:
const src = 'http://example.com/my-image.jpg';
preloadImage(src).then(image => {
// Here the image has been loaded and is available to be appended, or otherwise.
document.body.append(image);
});
In your case you would loop over each image, call the function while passing the URL of the image, and append the image to the DOM when it's finished loading.
You can handle any animations, like fade-ins with CSS.
Real world implementation
So how should you implement this in your project? You'll need to start at the point where you create your images. Currently your images are created as strings. But strings are just strings, they aren't HTML elements, yet.
I'd recommend that you'll create a placeholder for each image. This placeholder could visually indicate that an image is loading and act as a wrapper for the image. Add this placeholder immediately to the pItems element.
Then load the image for each Image in your data.projects array by calling the preloadImage. Whenever the image is loaded, append it to the placeholder we've just created. You should now have the effect that first a placeholder is added and the images are starting to appear one by one.
The same logic should be applied for the load more loop.
...
}).then(function (data){
for (let i = 0; i < itemsStart; i++) {
// Create a <div class="placeholder"> which should act as a placeholder / wrapper.
const placeholder = document.createElement('div');
placeholder.classList.add('placeholder');
// Create the image based on the Image value.
// Whenever the image is loaded, add it to the placeholder.
const src = data.projects[i].Image;
preloadImage(src).then(image => {
placeholder.append(image);
});
// Immediately add the placeholder.
// This line doesn't wait for preloadImage to finish because preloadImage is asynchronous. Look into Promises if that is new to you.
pItems.append(placeholder);
}
...
});
From here you've got control over how the placeholder should look and any animations an image inside that placeholder should have.
I think you could put a <div> with black background over the loading image using css and when the image is ready remove it with js. You can detect when the image is loaded using the img.onload = () => {} function.
Or you could place there an img with the loading screen and replace it with the actual image when the image has loaded.
This is my first post here, I always found solutions on this page, so thank you for that.
I have a problem with .removeClass and .addClass in my last program.
I load multiple pictures into array Frames and I want change all (previous-image) to (current-image) in frames[0]. Here is my code, it is change class only on second image. Here is code:
function loadImage() {
// Creates a new <li>
var li = document.createElement("li");
// Generates the image file name using the incremented "loadedImages" variable
var imageName = "graphics/img/Dodge_Viper_SRT10_2010_360_720_50-" + (loadedImages + 1) + ".jpg";
var imageName1 = "graphics/img/Dodge_Viper_SRT10_2010_360_720_50-" + (loadedImages + 1) + ".jpg";
/*
Creates a new <img> and sets its src attribute to point to the file name we generated.
It also hides the image by applying the "previous-image" CSS class to it.
The image then is added to the <li>.
*/
var image = $('<img>').attr('src', imageName).addClass("previous-image").appendTo(li) && $('<img>').attr('src', imageName1).addClass("previous-image light-image").appendTo(li);
// We add the newly added image object (returned by jQuery) to the "frames" array.
frames.push(image);
// We add the <li> to the <ol>
$images.append(li);
/*
Adds the "load" event handler to the new image.
When the event triggers it calls the "imageLoaded" function.
*/
$(image).load(function() {
imageLoaded();
});
};
function imageLoaded() {
// Increments the value of the "loadedImages" variable
loadedImages++;
// Updates the preloader percentage text
$("#spinner span").text(Math.floor(loadedImages / totalFrames * 100) + "%");
// Checks if the currently loaded image is the last one in the sequence...
if (loadedImages == totalFrames) {
// ...if so, it makes the first image in the sequence to be visible by removing the "previous-image" class and applying the "current-image" on it
frames[0].removeClass("previous-image").addClass("current-image");
/*
Displays the image slider by using the jQuery "fadeOut" animation and its complete event handler.
When the preloader is completely faded, it stops the preloader rendering and calls the "showThreesixty" function to display the images.
*/
$("#spinner").fadeOut("slow", function() {
spinner.hide();
showThreesixty();
});
} else {
// ...if not, Loads the next image in the sequence
loadImage();
}
};
This is, how it looks in browser:
<ol><li><img src="graphics/img/Dodge_Viper_SRT10_2010_360_720_50-1.jpg" class="previous-image"><img src="graphics/img/Dodge_Viper_SRT10_2010_360_720_50-1.jpg" class="light-image current-image"></li></ol>
This is, what I want:
<ol><li><img src="graphics/img/Dodge_Viper_SRT10_2010_360_720_50-1.jpg" class="current-image"><img src="graphics/img/Dodge_Viper_SRT10_2010_360_720_50-1.jpg" class="light-image current-image"></li></ol>
When I change this
var image = $('<img>').attr('src', imageName).addClass("previous-image").appendTo(li) && $('<img>').attr('src', imageName1).addClass("previous-image light-image").appendTo(li);
to this
var image = $('<img>').attr('src', imageName1).addClass("previous-image light-image").appendTo(li) && $('<img>').attr('src', imageName).addClass("previous-image").appendTo(li);
it still change only second img. Any help?
var image = $('<img>').attr('src', imageName).addClass("previous-image").appendTo(li) && $('<img>').attr('src', imageName1).addClass("previous-image light-image").appendTo(li);
is not doing what you think it is. It's only using the second element you declare. They both get appended to the page (because the appendTo method runs), but && is a logical operator, it's not used for concatenation, so the variable "image" only contains the second image you declared.
This will work instead:
var image = $('<img>', { "src": imageName, "class": "previous-image" });
image = image.add($('<img>', { "src": imageName1, "class": "previous-image light-image" }));
image.appendTo(li);
If you are just trying to replace all the previous-image classes with current image then you can do this:
$('img.previous-image').each(function(){
$(this).addClass("current-image").removeClass("previous-image");
});
Here i am trying to download image using jquery and adding downloaded images to DOM. To check if image has been loaded or not i m using "https://github.com/desandro/imagesloaded"
For that i have taken a temporary div(temp-images-div) and adding images there.then i am replace the src to actual div (multimedia-div).
function populateImageResults(allImagesData) {
// populate response data for later use
responseData = allImagesData;
//append html as hidden element to body
var html = '';
jQuery.each(responseData, function(index, val) {
html += '<img id=\"image-'+index+'" src="'+val.THUMBURL+'">';
});
html = '<div id="temp-images-div" style="display:none">'+ html + '</div>';
$('body').append(html);
$('img[id^="image-"]').imagesLoaded()
.progress(function (instance, image) {
var imgId = image.img.id;
if (image.isLoaded) {
var imgSrc = image.img.src;
$('#lemmon-slider-id ul').append('<li><img id="'+imgId+'" src="'+imgSrc+' style="height:100px"></li>');
} else {
// if image not loaded then store broken image id into array
brokenImageIDs.push(imgID);
}
})
.always(function() {
// always event will be triggered after all images have been either loaded or confirmed broken
// currently do nothing
// FIXME - load broken images here
});
// delete temporary div '#temp-images-div'
jQuery("#temp-images-div").remove();
// display multimedia div
jQuery('#multimedia-div').css('display','block');
}
Now i am checking Images are being loaded twice. But I want to use pre-loaded image.I can understand why it is loading twice but i do not want this.
So my question is how to use already loaded image? I need to keep the structure of html similar as provided in above jquery code.
<Ul>
<li><img ..></li>
<li><img ..></li>
....
...
</ul>
The javascript of the div "intro" is loading at last. It's taking too long to load as the web page loads the bg image first and then loads the java script. Is there a way i can display "loading please wait" message in that "intro" div until it completely loads. I just want that the intro should load first.
Javascript code:
var tl = new Array(
"=======================",
" Welcome user, ",
" ###########################################"
);
var speed = 50;
var index = 0;
text_pos = 0;
var str_length = tl[0].length;
var contents, row;
function type_text() {
contents = '';
row = Math.max(0, index - 20);
while (row < index)
contents += tl[row++] + '\r\n';
document.forms[0].elements[0].value = contents + tl[index].substring(0, text_pos) + "_";
if (text_pos++ == str_length) {
text_pos = 0;
index++;
if (index != tl.length) {
str_length = tl[index].length;
setTimeout("type_text()", 500);
}
}
else setTimeout("type_text()", speed);
}
This is the script and its basically typing letter by letter in a text area in the div "intro". The problem is that it loads at last when the whole page has loaded. It starts printing the text after like 15 seconds or so.
There are "domready" events you can listen to on the document but seems that's not cross-browser.
Eg: Mozilla
document.addEventListener("DOMContentLoaded", methodName, false)
A better option is to use jQuery's .ready() event. They handle all cross-browser implementations.
Eg:
$(document).ready(function(){
//execute code here
});
//Shorthand
$(function(){
//...
});
See this related question for more on domready.
Load a page with the empty intro div, run the script with "loading please wait" then trigger an ajax request to load the rest of the page and update the page on onComplete event from the ajax request
Using jQuery
$(document).ready(function() {
// update div here
});
http://api.jquery.com/ready/
Or you could do that with
window.onload= (function() {
// update div here
};
You can use jquery for this by wrapping the content in a div tag and then another div that holds a loading image, something to this effect:
$(document).ready(function () {
$('#loading').show();
$('#divShowMeLater').load(function () {
$('#loading').hide();
$('#divShowMeLater').show();
});
})
Assume divShowMeLater is the div that contains all the content being loaded. The markup would look similiar to this:
<div id="divShowMeLater" style="margin-left:auto;margin-right:auto;text-align:center;" >
<div id="loading">Page loading...
<img src="images/ajax-loader.gif" alt="loading page..." />
</div>
</div>
I have multiple anchor tags with a rel="<img src"#"/>".
When I click on any <a></a>, I show a large image in another div with the rel value using a fadeIn effect.
What I want to do is check if the large image has the same src as the rel of the anchor and prevent the fadeIn effect if so.
$(document).ready(function () {
$("a.largeimg").click(function () {
var image = $(this).attr("rel");
$('.main-product-image').html('<img src="' + image + '"/>');
$('.main-product-image img').hide();
$('.main-product-image img').fadeIn();
return false;
if(src == image) {
$('.main-product-image img').show();
}
});
You can check if the rel of the anchor and the src of the image are the same and if so escape the function before the fade in code, like so:
var src = $('.main-product-image img').attr("src");
if (src == image) return false;
If I understand you question correctly, before the animation you need to confirm if the src of the image is equal to the rel attribute of the clicked element, thus preventing the animation!
JQUERY
$(document).ready(function () {
// use bind when targeting many elements
$("a.largeimg").bind("click", function () {
var $target = $('.main-product-image'), // target element
src = $target.find('img').attr("src"), // src from existent image
image = $(this).attr("rel"); // rel from clicked element
// if src different from image
if (src != image) {
$target.html('<img src="' + image + '"/>'); // append new image
$target.find('img').hide().fadeIn(); // perform the animation
}
// prevent the browser from continuing to bubble the clicked element
return false;
});
});
Ps:
Not tested, but should work just fine!