How to make a list of image links in jQuery? - javascript

I have a list of links. What I want to do is attach a function to each link with jQuery; when the link is clicked, the function will run, and a pair of images will be loaded into a div (img ids "img1" and "img2"). Each link has the class "link", and will load a different pair of images. So, the first link will load Image 1A and Image 1B, the second will load Image 2A and 2B, and so on. I have the images in two arrays.
However, instead of attaching the calls like I want, it ends up loading the last two images of the arrays, after the page stops loading. What's more, clicking on the links does nothing!
var loadImages =
{
init: function()
{
var links = $( ".link" );
myArray1 = [
"imgs/png/image1.png",
"imgs/png/image2.png",
"imgs/png/image3.png",
];
myArray2 = [
"imgs/jpg/image1.jpg",
"imgs/jpg/image2.jpg",
"imgs/jpg/image3.jpg",
];
for ( var i = 0, ii = links.length; i < ii; i++ )
{
$( links[ i ] ).bind( "click", loadImages.imgLoader( myArray1[ i ],
myArray2[ i ] ) );
}
},
imgLoader: function( firstURI, secondURI )
{
document.getElementById( "img1" ).src = firstURI;
document.getElementById( "img2" ).src = secondURI;
}
};
loadImages.init();

You don't bind a callback function. You execute loadImages.imgLoader and pass the result.
Normally you could just bind a callback function, but since you're using a counter variable within the callback itself, you need to be wary of the scope of i:
$(links[i]).on("click", (function(j) {
return function() {
loadImages.imgLoader(myArray1[j], myArray2[j]);
}
})(i));
A better approach would be to bind the event handler to all of the links at once and handle the image swapping without a for loop:
$('.link').click(function() {
var index = $(this).index();
$('#img1').prop('src', myArray1[index]);
$('#img2').prop('src', myArray2[index]);
});

Try Using the .each() method.
var loadImages = {
init: function(){
var myArray1 = ['imgs/png/image1.png', 'imgs/png/image2.png', 'imgs/png/image3.png'];
var myArray2 = ['imgs/jpg/image1.jpg', 'imgs/jpg/image2.jpg','imgs/jpg/image3.jpg'];
$('.link').each(function(i){
$(this).click(function(){
loadImages.imgLoader(myArray1[i], myArray2[i]);
});
});
},
imgLoader: function(firstURI, secondURI){
$('#img1').attr('src', firstURI);
$('#img2').attr('src', secondURI);
}
};
loadImages.init();
Also, you should use the keyword var so your variables don't have a global scope, and remove commas at the end of your Arrays. Visit http://api.jquery.com/each/ for more information on .each().

Related

Remove dynamically added div on timer

I'd like a div to appear for a short duration of time and then go away.
So, I dynamically create the div on the click of a button, and then after some work is done, I'd like it to be removed from the DOM.
So, I set up a timer like so:
var contentJoinTab = $("#...");
var divIdSubscribePleaseWait = "div-subscribe-pleasewait";
btnSubscribe.on("click", function (event) {
displaySubscriptionWait();
postMailingListSubscription();
});
function displaySubscriptionWait() {
var s = `<div id = ${divIdSubscribePleaseWait} class = "${classMailingListPleaseWait}">Please wait...</div>`;
contentJoinTab.append(s);
};
function postMailingListSubscription() {
// fake for now
window.setTimeout(function() {
removeSubscriptionWait();
}, 4000);
};
function removeSubscriptionWait() {
contentJoinTab.parent(`${divIdSubscribePleaseWait}`).remove();
// I've even tried the following to no avail
// $(`${divIdSubscribePleaseWait}`).remove();
// contentJoinTab.find(`${divIdSubscribePleaseWait}`).remove();
};
However, even though there is no error in the call to the remove() method, the div I am trying to remove remains in the DOM and is visible.
I do understand event propagation but my understanding is that that's not relevant here. That would have been relevant if I wanted to attach an event to the click (or any other event) of the dynamically created div or any of its parent.
You may be missing # when calling removeSubscriptionWait And also need "" for id = ${divIdSubscribePleaseWait}.
Please see changes below in case it isn't clear:
function displaySubscriptionWait() {
var s = `<div id = "${divIdSubscribePleaseWait}" class = "${classMailingListPleaseWait}">Please wait...</div>`;
contentJoinTab.append(s);
};
function postMailingListSubscription() {
// fake for now
window.setTimeout(function() {
removeSubscriptionWait();
}, 4000);
};
function removeSubscriptionWait() {
contentJoinTab.parent(`#${divIdSubscribePleaseWait}`).remove();
// I've even tried the following to no avail
$(`#${divIdSubscribePleaseWait}`).remove();
};
You can do that by setting outerHTML of that div to null
function addDiv() {
let s = "<div id='tempDiv'>Temporary Div</div>"
let root = document.getElementById("root")
root.innerHTML += s;
}
function removeDiv() {
let theDiv = document.getElementById("tempDiv");
theDiv.outerHTML=""
}
addDiv()
setTimeout(removeDiv,2000)
<div id=root>
</div>
You have appended that div as a child of contentJoinTab but when you go to remove it you are looking for it as being parent of contentJoinTab
You also need to add the ID prefix in selector
try changing
contentJoinTab.parent(`${divIdSubscribePleaseWait}`).remove();
To
contentJoinTab.find(`#${divIdSubscribePleaseWait}`).remove();
update removeSubscriptionWait function :
function removeSubscriptionWait() {
contentJoinTab.find('#'+`${divIdSubscribePleaseWait}`).remove();
};

Jquery .change() event fires only once

So I'm fairly novice with jquery and js, so I apologise if this is a stupid error but after researching I can't figure it out.
So I have a list of data loaded initially in a template, one part of which is a dropdown box that lets you filter the data. My issue is that the filtering only works once? As in, the .change function inside $(document).ready() only fires the once.
There are two ways to reload the data, either click the logo and reload it all, or use the search bar. Doing either of these at any time also means the .change function never fires again. Not until you refresh the page.
var list_template, article_template, modal_template;
var current_article = list.heroes[0];
function showTemplate(template, data)
{
var html = template(data);
$("#content").html(html);
}
$(document).ready(function()
{
var source = $("#list-template").html();
list_template = Handlebars.compile(source);
source = $("#article-template").html();
article_template = Handlebars.compile(source);
source = $("#modal-template").html();
modal_template = Handlebars.compile(source);
showTemplate(list_template,list);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = list.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
$("#classFilter").change(function()
{
console.log("WOW!");
var classToFilter = this.value;
var filteredData =
{
heroes: list.heroes.filter(function(d)
{
if (d.heroClass.search(classToFilter) > -1)
{
return true;
}
return false;
})
};
console.log(filteredData);
showTemplate(list_template,filteredData);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = filteredData.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
});
$("#searchbox").keypress(function (e)
{
if(e.which == 13)
{
var rawSearchText = $('#searchbox').val();
var search_text = rawSearchText.toLowerCase();
var filteredData =
{
heroes: list.heroes.filter(function(d)
{
if (d.name.search(search_text) > -1)
{
return true;
}
return false;
})
};
console.log(filteredData);
showTemplate(list_template,filteredData);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = filteredData.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
}
});
$("#logo").click(function()
{
showTemplate(list_template,list);
$(".articleButton").click(function()
{
var index = $(this).data("id");
current_article = list.heroes[index];
showTemplate(article_template,current_article);
$('.poseThumb').click(displayModal);
});
});
//$("#logo").click();
});
function displayModal(event)
{
var imageNumber = $(this).data("id");
console.log(imageNumber);
var html = modal_template(current_article.article[0].vicPose[imageNumber]);
$('#modal-container').html(html);
$("#imageModal").modal('show');
}
I should note two things: first, that the search bar works perfectly, and the anonymous function inside both of them is nearly identical, and like I said, the filtering works perfectly if you try it after the initial load. The second is that the same problem occurs replacing .change(anonymous function) with .on("change",anonymous function)
Any help or advice would be greatly appreciated. Thanks.
I agree with Fernando Urban's answer, but it doesn't actually explain what's going on.
You've created a handler attached to an HTML element (id="classFilter") which causes part of the HTML to be rewritten. I suspect that the handler overwrites the HTML which contains the element with the handler on it. So after this the user is clicking on a new HTML element, which looks like the old one but doesn't have a handler.
There are two ways round this. You could add code inside the handler which adds the handler to the new element which has just been created. In this case, that would mean making the handler a named function which refers to itself. Or (the easier way) you could do what Fernando did. If you do this, the event handler is attached to the body, but it only responds to clicks on the #classFilter element inside the body. In other words, when the user clicks anywhere on the body, jQuery checks whether the click happened on a body #classFilter element. This way, it doesn't matter whether the #classFilter existed when the handler was set. See "Direct and delegated events" in jQuery docs for .on method.
Try to use some reference like 'body' in the event listeners inside your DOM like:
$('body').on('click','.articleButton', function() {
//Do your stuff...
})
$('body').on('click','#classFilter', function() {
//Do your stuff...
})
$('body').on('keypress','#searchbox', function() {
//Do your stuff...
})
$('body').on('click','#logo', function() {
//Do your stuff...
})
This will work that you can fire it more than once.

Invoke function once, only after JQuery created images are loaded

I've been searching for a solution but all i'm getting is $(window).on("load", fuction(){}) which just loads the html resources.
I'm creating a variable amount of images and inserting them in a div with jquery using an each() function after the window is loaded.
$.each(footeradds, function(fad){
$("<div class=\"footerads\"><img src=\"image" + fad + ".jpg\"/></div>").appendTo(".footer");
});
I need to calculate the width of the container of these images which depends on the amount of images and their width, which they only have after they've loaded.
if i do
$(".footer img").on("load", function() {})
that function is called every time an image loads, and need it to only be called once, after ALL images have loaded.
My question is: how can i invoke a function after images created with jquery are loaded?
there is no methods for it but you can do one thing
take a variable A = count all images , then create other variable B = 1 and increment it on every image load and
check condition A == B
that condition will true when last image will called .....:)
Turn the event off after first time
$(".footer img").on("load", function() {
$( this ).off( event );
})
So i ended up using Pratik Bhalodiya's idea and made this:
var footerW = 0;
var fimgs = 0;
$(".footer img").on('load', function() {
footerW += + $(this).width();
fimgs++;
if (fimgs == $(".footerads").length){
//do stuff here
}
});
thanks for your help everyone!
You could just use a deferred for each image, and $.when to check that all are resolved etc
var p = $.map(footeradds, function(fad){
var def = new $.Deferred,
div = $('<div />', {
'class' : 'footerads'
}),
img = $('<img />', {
on : {
load : function() {
def.resolve(this);
}
},
src : 'image' + fad + '.jpg'
});
$(".footer").append( div.append(img) );
return def.promise();
});
$.when.apply($, p).then(function(images) {
// all images loaded
var images = [].slice.call(arguments);
// use images here
});

Generate input handler via jQuery for xmlhttprequest json data in a table

I'm struggling with dynamic generation of buttons over a JSON array.
Stripped-down code is this (aim is to build a table based on the data, nothing fancy yet, I'm not yet proficient at this):
$.ajax({
/* type, content, etc. removed */
success: function (data, textStatus, XmlHttpRequest) {
var target = $('myContainerDiv');
var result = data.d.results;
var $table = $('<table />');
for(var i=0;i < results.length; i++) {
var $row = $('<tr />');
var $cell = $('<td />');
var $button = $('<input />').attr({ type: 'button', value: 'Edit', name: 'btn' + i });
$button.click(function () {
// **
// In a .NET environment, this would become a closure
// I suspect this is the offending bit of code
//
alert(results[i].name);
};
$cell.append($button);
$row.append($cell);
$table.append($row);
}
$target.append($table);
},
/* error etc. removed*/
});
I basically want a column filled with buttons, each one would popup the value of a field from the array I get from my $.ajax call.
Buttons actually show up, but they do not react to clicking, and I see no runtime error in the F12 tools console. This is probably due to the fact that this script is part of the configuration page for a Microsoft Dynamics CRM 2011 Solution, but other than that, I'm sure the AJAX call goes on OK (I tried making it print out data, and I can see it).
UPDATE
Referencing i inside the click handler was the offending line indeed: changed the code like this made things work as I was expecting:
var $button = $('<input />').attr({ type: 'button', value: 'Edit', name: 'btn' + results[i].name });
$button.click(function () {
// 'i' value is NOT what I thought it was !
alert(this.name.substring(3,this.name.length));
// I found out in the meanwhile that 'this' references the event source
};
First you have several syntax errors in your code and it may not be running at all:
if the ID of your div container is myContainerDiv, to get the target you need to do $('#myContainerDiv')
you create a result varialbe, but you use a results variable
you're not closing the parentesis in the $button.click
you're adding everything to $target but is defined as target
Now the actual problem may be, as you say, the closure, remember that you close over variables not values, so when you execute the button click handler, i has a value of results.length, so you are out of bounds by that time.
You could try to store the results objects elsewhere, extract the Id of the object your looking for from the button (you're naming then 'btn'+i) and then access the name property that way.
I noticed you didn't close the .click() bracket.
Try...
$button.click(function () {
alert(results[i].name);
});
You can try this ...
$.ajax({
/* type, content, etc. removed */
success: function (data, textStatus, XmlHttpRequest) {
var $target = $('#myContainerDiv'),
results = data.d.results,
$table = $target.append('<table />').children('table:last-child'), $trSet = $([]);
for(var i=0; i < results.length; i++) {
$trSet = $trSet.add(
$([
'<tr><td>',
$('<input type="button" value="edit" name="btn'+i+'" rel="'+results[i].name+'" />').wrap('<div />').html(),
'</td></tr>'
].join(''))
);
}
// Using Event delegation ... Only one handler is attached to the DOM.
$table.append($trSet).click(function(e){
var $t = $(e.target);
if( $t.is('input[type="button"]') ){
alert($t.attr('rel'));
}
// choose to return false whether to prevent event bubbling up the DOM or not
// return false;
});
},
/* error etc. removed*/
});

Only last item has bound click/hover events?

I'm a newbie to Javascript & HTML5. I'm iterating through a set of objects called requests and creating divs for them. I'm trying to have it so that if any of the items are hovered over the style class changes, and if they are clicked on that I will later invoke a function but for now just want an alert. Only the last item gets it.
I've looked at what seemed like similar issues other people have had, but I can't see where I am going wrong.
for (i= 0; i<reqs.length; i++) {
var requestID = "request"+i;
// Build the DIV for each request
element.innerHTML += "<div id="+requestID+" class=request><img class=requestImage src=images/"
+reqs[i].image+" alt=Face /> "+reqs[i].name+"</div>";
var requestElement = $('#'+requestID);
requestElement.hover(
function() {
$(this).removeClass().addClass("requestHover");
},
function() {
$(this).removeClass().addClass("request");
}
);
requestElement.click(
// if the request is clicked, then alert me - testing
function() {
alert('Handler for .click() called.');
}
);
}// end for
From my understanding the $('#request1') should reference the first div item, and $('#request2') the second, etc. It behaves like each .hover and .click assignment overwrites the previous one.
I'd write it this way
for (i= 0; i<reqs.length; i++) {
var requestID = "request"+i;
// Build the DIV for each request
element.innerHTML += "<div id="+requestID+" class=request><img class=requestImage src=images/"
+reqs[i].image+" alt=Face /> "+reqs[i].name+"</div>";
}// end for
var requestElement = $(".request");
requestElement.hover(
function() {
$(this).removeClass().addClass("requestHover");
},
function() {
$(this).removeClass().addClass("request");
}
);
requestElement.click(
// if the request is clicked, then alert me - testing
function() {
alert('Handler for .click() called.');
}
);
Edit to answer to your comment:
No, it's a matter of closure. At the end of the loop, requestID is always the same, so $("#"+requestID); is always the same. It's has if there is only one bind.
To overcome such a thing, you have some option:
using $.each to loop (see http://forum.jquery.com/topic/binding-event-to-element-dynamically , http://forum.jquery.com/topic/binding-click-event-in-a-loop, http://api.jquery.com/jQuery.each/ )
using the live() method (see http://api.jquery.com/live/, http://jsfiddle.net/VrzUb/1/ (used for the click))
assigning the events thanks to a selector common to each object (e.g. using classes, as above)
You can assign the event listener after the for loop, maybe that solves your problem:
for (...) {
}
$('div.request').hover( ... );

Categories

Resources