adding inline styling on appended items on run time having issues - javascript

I have an "a" tag into a "li" and am appending few images on hover of a "li" into same "a" tag and I have to use inline style on all those img elements but the problem is when I hover first time on "li" these styles apply only on first img tag which is always exist there but not on others but if I hover over "li" again then those inline styles applies on all img tags. for this am using this JS code given below:
$(document).ready(function() {
var mouseover_interval;
var $image;
$('li.product-details').mouseenter(function() {
current_image = -1;
$image = $(this).find('a.current_product_image img');
data_srcs = $image.attr('data-srcs').split(",");
if(data_srcs.length >1){
for (var i = data_srcs.length - 1; i >= 0; i--) {
img = new Image ;
img.src = data_srcs[i];
new_img = $('<img>').attr('src', data_srcs[i]).css({display:"none"}).addClass("over");
$(this).find('a.current_product_image').append(new_img);
var countImg = $(this).find('a.current_product_image img');
countImg.each(function(){
$(this).css({
position : 'absolute',
left : '50%',
marginLeft : -$(this).width()/2,
top : '50%',
marginTop : -$(this).height()/2,
});
});
}
}
else{
return false;
}
$images = $(this).find('a.current_product_image img.over');
mouseover_interval = setInterval(function(){
{
$image.fadeOut(500);
if(current_image == -1){
$($images[$images.length-1]).fadeOut(500);
}
else{
$($images[current_image]).fadeOut(500);
}
current_image+=1;
$($images[current_image]).fadeIn(500);
if(current_image == $images.length-1){
current_image = -1;
}
}
}, 1000);
}).mouseleave( function(){
clearInterval(mouseover_interval);
$image.fadeIn(500);
$(this).find('a.current_product_image img.over').remove();
});
});
How to add styles on all appended elements hovering over "li" first time? Please let me know if am using anything wrong there.
Thanks in advance,
Ashwani Sharma

The reason this is happening is - most likely - the additional images haven't loaded into the DOM yet (remember that it takes time for assets - particularly images - to load when you add them in dynamically).
To confirm this, try logging the countImg var and see whether it reports one too few for the number of images you expect to have. I suspect that's your issue.
You could try passing attributes into the element before adding it into the page. Something like this:
new_img = $('<img>', {
src: data_srcs[i],
class: 'over'
}).hide();
This should create an object that looks like:
<img src="your/source.jpg" class="over" style="display: none;" />
Your problem will still be that it won't actually load into the page until you turn off the display: none, most browsers are intelligent enough to not pull images until they are actually needed (ie: not when hidden).
Also note that your declaration of $image is only set once, at the very beginning of the function. It therefore will only contain the elements it finds at that point in time. If you dynamically add additional images (ie: your new_img)to the parent element, they won't automatically get added to that $image variable.

Related

Accessing items in Javascript Node List to alter image

I am trying to create the same effect of CSS Hover but with Javascript code (for the purpose of learning Javascript and for future use). So on mouseover, I would like the individual image to increase opacity.
The code I have written below does not work. Please see comments for explantion regarding what I am trying to do;
<script>
//gets all img tags (qu.20)
var images = document.getElementsByTagName("img")
// Create new element with id "newNode" for the individual node to go into
var node = document.body.createElement("newNode")
// Add the new element into the html document
document.body.appendChild(newNode)
// Attach var i to the individual nodes and set src of new element as that node
function overImage () {
for (var i=0; i<images.length; i++) {
document.getElementById("newNode")
document.body.newNode.src = images.item(i)
}
}
// function to create a new class with same attributes as original when mouse leaves image
function leaveImage () {
for (var i=0; i<images.length; i++) {
document.getElementById("newNode")
document.body.newNode.src = images.item(i)
document.body.newNode.className = " leave"
}
}
</script>
<html>
<img src="image1.gif" onmouseover="overImage()" onmouseout="leaveImage()" alt="image" />
<img src="image2.gif" onmouseover="overImage()" onmouseout="leaveImage()" alt="image" />
</html>
<style>
img { opacity:0.5; }
#newNode { opacity:1; }
#newNode.leave { opacity:0.5; }
As an alternative, this code works but only on all images (ie. they all change opacity together, not individually.
<script>
function overImage () {
var selectImage = document.getElementsByTagName("img")
for (var i=0; i<selectImage.length; i++) {
selectImage[i].className = " over"
}
}
function leaveImage () {
var selectImage = document.getElementsByTagName("img")
for (var i=0; i<selectImage.length; i++) {
selectImage[i].className = ""
}
}
</script>
<style>
img { opacity:0.5; }
.over { opacity:1; }
</style>
Answers in Javascript only please with explanations. No jquery
You can do this in a much simpler manner, check this example:
var f = function(e) {
// the event target, can be any element in the page at this point
var t = e.target;
// check if the event target is an img element
if(t.tagName.toLowerCase() == 'img') {
// then toggle its active class
t.classList.toggle('active');
}
}
// add listeners to the window (or on whatever image container you have)
addEventListener('mouseover', f /* call this function f on mouseover */, false);
addEventListener('mouseout', f, false);
img { opacity: .5; }
.active { opacity: 1; }
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
<img src='http://i.imgur.com/kk7fJccs.jpg'/>
This code is going to work no matter how many images you add after this. It eliminates for you to add calls to your JS functions (whose names you may choose to change) to the HTML, the need for messing with the DOM from JS, the need for looping in the JS. And as far as the CSS is concerned, it's not using ids for styling, so it's avoiding specificity issues.
Your issue appears to be right at the top, document.body.createElement("newNode") will give you a TypeError: undefined is not a function. The createNode method is on the #document node, not a HTMLElement.
Next, you create nodes by tag name, there is no such tag <newNode>, maybe you meant to create an <img>
var node = document.createElement("img");
Now you need to assign the id attribute to it,
node.setAttribute('id', 'newNode');
Next, you have to append node to your document tree (you're currently trying to append an undefined variable newNode)
document.body.appendChild(node);
Finally, your two functions overImage and leaveImage have several problems of their own;
They are performing document.getElementById but not remembering the result, instead trying to go through the DOM tree in an unusual way and also you're trying to assign a node as a src, when you probably want to assign a String
// outside loop
var node = document.getElementById("newNode");
// inside loop
node.src = images.item(i).src;
They loop over all of images each time, meaning you will always finally end up with node's src pointing at the value from the last item in images
Try linking up these listeners using foo.addEventListner(type, event_handler) where foo is a reference to each node you want to attach the event_handler to. This will let you access the mouseover or mouseout event in more detail, especially if event_handler looks at it's first argument which will be the event itself, or this which will be the node which invoked the handler.
Always check your console as the first step in debugging, it'll usually let you quickly narrow down your issue to the exact line with the problem

How to change the css attribute of #header using jQuery and an array of images?

I am trying to edit a script that changes the images of a div as shown below, to change the background-image property of #header.
As you can see in my fiddle here, http://jsfiddle.net/HsKpq/460/ I am trying to show the images into the $('#header').css('background-image',..................).fadeTo('slow',1);
How can I do this? I guess I have to change some other parts too..
var img = 0;
var imgs = [
'http://www.istockphoto.com/file_thumbview_approve/9958532/2/istockphoto_9958532-sun-and-clouds.jpg',
'http://www.istockphoto.com/file_thumbview_approve/4629609/2/istockphoto_4629609-green-field.jpg',
'http://www.istockphoto.com/file_thumbview_approve/9712604/2/istockphoto_9712604-spring-sunset.jpg'
];
// preload images
$.each(imgs,function(i,e){var i=new Image();i.src=e;});
// populate the image with first entry
$('img').attr('src',imgs[0]);
var opacity = 0.1; // change this for minimum opacity
function changeBg() {
$('img').fadeTo('slow',opacity,function(){
$('#header').css('background-image',..................).fadeTo('slow',1);
});
}
setInterval(changeBg,5000);
You need a couple of fixes:
Use a simple increment to keep track of the current image.
typo: "images" -> "imgs"
$("img") doesn't select anything, so the JQuery fadeto "complete" callback is never fired (I assume you meant to fade the div itself)
you need "url('http://...')" for the "background-image" CSS property
function changeBg() {
if (i >= imgs.length) i=0;
$('#header').fadeTo('slow',opacity,function(){
var val = "url('" + imgs[i++] + "')";
console.log(val);
$('#header').css('background-image',val).fadeTo('slow',1);
});
}
Here is the updated demo.

Need to fix JavaScript so that the array begins at the right position

Hi I have got a jsFiddle to share but never used it before so I hope I did it right..
http://jsfiddle.net/Mayron/3V62C/
I also have these screen shot to better show what I mean:
http://i.imgur.com/NgQk5P2.jpg
I have a table of images in the gallery page and when you click on an image it opens up a frame that shows a blank but much larger image which gains the source of the smaller image you clicked on. That works fine but I have all the images in the gallery listed in an array and the large frame has three buttons on it: previous, close and next. So far the JavaScript code allows you to click next and previous to go through them but it always begins the journey from array[0] and that is no good if you click to view the 6th one in the list from the gallery page first for example.
I hope that makes sense if not then let me know!
The issue is with this line that causes it to begin from the first image:
currentIndex = 0;
How can I change this so that the currentIndex number is the image that the user first clicks on?
There are several ways but that really depends on what you use and how clean you want your code to look. I put a hidden input in each of my divs and retrieve it with JQuery's $("input", $(this).parent()).val();
You could also use Jquery's index. http://api.jquery.com/index/
You could have it in a class and retrieve the class of the clicked item (same idea as having an ID for each image)
On click you can have a selector added in the class attribute then you can use a for-each to count how many images go through before you hit that class in your image order.
You could also do showLarge(this, index#) and set the index that way. I cannot get your JS fiddle to work though.
Do this for every image line:
<td><a href="#" onclick="javaScript:showLarge(this,1);" ><img class="imgBorder" id="image1" src="Media//Gallery//img_1.jpg" alt="Gallery Image 1" /></a>
</td>
This puts onclick in anchor tag and adds an id in the image tag named image1 (1 is the number you put in the anchor tag 2nd param)
In javascript, do:
function showLarge(img, index) {
var largeFrame = document.getElementById("zoomedIn");
largeFrame.style.visibility = 'visible';
var largeImage = document.getElementById("largeImage");
src = document.getElementById("image"+index);
largeImage.src = src.src;
currentImage = index;
}
This gets the image by id according to index clicked
For the next+prev button do:
function changeImage(direction) {
index = parseInt(currentIndex) + parseInt(direction);
if (index < 1) {
index = 1; // or use imgArray.length to rotate round
}
if (index > imgArray.length) {
index = imgArray.length; // or use 0 to rotate round
}
src = document.getElementById("image"+index);
document.getElementById('largeImage').src = src.src;
currentIndex = index;
}
Try something like this:
function findIndex(src) {
for (i = 0; i = imgArray.length; i++)
if (imgArray[i].src == src) {
currentIndex = i;
return;
}
}
function showLarge(img) {
var largeFrame = document.getElementById("zoomedIn");
largeFrame.style.visibility = 'visible';
var largeImage = document.getElementById("largeImage");
largeImage.src = img.src;
findIndex(img.src);
}
It will update the currentIndex value.
I've updated your jsfiddle: http://jsfiddle.net/RN4bN/
But I can't run it, so try directly on your code.
Put an ID on each of them which is the number of it from the array, then when it is clicked change the currentIndex to that.

Removing a div with no id or class with Javascript

My wordpress blog is having issues with syntax highlighter evolved plugin, and there's this weird div element popping out:
<div style="z-index: -1; position:absolute; top:0px; left: 0px; width: 100%; height: 4031px;"></div>
This causes my page to extend, creating a big space at the end of the page. This also is found on every wordpress blog. Funny thing is, only chrome sees that (using Inspect Element). I've already tried in IE9 developer tools and FF firebug, the div is not there and my page is fine.
NOTE: I've already posted a separate question here. And my question here is different from that.
I want to fix this little problem so bad, and it just came to my mind to use JavaScript for this. What I want to do is: Remove the div with javascript.
It's easy removing a div with an ID or class, but this one doesn't have any. I also do not want to affect all the other divs. How can I accomplish this?
P.S. It has no parent IDs or class. It's right after the container class div. It's parent is <body>.
EDIT: Here's the html:
If it's always last or close to last you can use jQuery or normal CSS3 selectors
$('body > div:last-child').remove();
OR
$('body > div:nth-last-child(n)').remove();
More on CSS3 Selectors and .remove()
OR you could use CSS i.e.
body > div:last-child (or div:nth-last-child(n)) {
display: none;
}
You could do something like this:
var els = document.getElementsByTagName('div');
for (var i = 0; l = els.length; i < l; i++) {
if (els[i].innerHTML == 'style....') {
els[i].parentNode.removeChild(els[i]);
}
}
If you are using jQuery, You can reference the div using a parent or sibling div that might have an ID or class defined.
For examample :
<div id="parentDIVID">
<div>your problem div</div>
</div>
Then you can use jQuery to reference your problem div like this : $("#parentDIVID > div")
If you can provide more html code surrounding your problem div, we can construct a jQuery selector that will work in your case.
Update : Based on the markup provided
function removeDiv() {
var parent = document.getElementById("stimuli_overlay").parentNode;
var children = document.getElementById("stimuli_overlay").parentNode.childNodes;
for (var i = 0; i < children.length; i++) {
if (children[i].style.zIndex == -1)
parent.removeChild(children[i]);
}
}
Update: Based on the fact that you can't rely on the div used below.
If the div really is the always the last div in the document, this is actually easier:
var divs, div;
divs = document.getElementsByTagName("div");
if (divs.length > 0) {
div = divs.item(divs.length - 1);
div.parentNode.removeChild(div);
}
Live example
length - 1 will remove the last div in the document. If you needed to skip a lightbox div or something, adjust to use - 2 or - 3, etc.
Old Answer using the earlier information:
Given that structure, something along these lines:
// Get the div that follows it, which conveniently has an ID
var div = document.getElementById('stimuli_overlay');
// If that worked...
if (div) {
// ...move to the previous div, with a bit of paranoia about blank non-element
// nodes in-between
div = div.previousSibling;
while (div && (div.nodeType !== 1 || div.tagName !== "DIV")) {
div = div.previousSibling;
}
// Check that this really is the right div
if (div && div.tagName === "DIV"
// The following checks look for some of the style properties that your
// screenshot shows are set on the div
&& div.style.position == "absolute"
&& div.style.zIndex == "-1"
&& div.style.top == "0px"
&& div.style.left == "0px"
&& div.style.width == "100%"
&& /* ...possibly more checks here... */) {
// Remove it
div.parentNode.removeChild(div);
}
}

JQuery .each() callback function doesn't run on each iteration/loop

Here's what should happen.
1. Get the rel attribute of the clicked link
2. For every div with class 'entry':
(i)Get its 'left' position
(ii) Calculate its outer height
(iii)Loop through all instances of 'a.tag_filter'. If it finds the same string in the 'rel' as the one oringinally clicked on then add 1 to 'V' and break out of the loop.
(iv)If 'V' is equal to 0 after the loop we know the same tag isn't present within that '.entry' so fade it out.
(v)Once the fadeout has finished loop through all the '.entry' after the faded out one and get their 'left' values.
(vi)If the left value of the faded entry = the left value of the current '.entry' then reposition it to the new 'top' value.
What is currently happening.
It runs through and fades out all the correct '.entry' elements and only after all of them have faded out does it reposition them remaining '.entry' elements.
After each element is faded out I would like the repositioning loop to run so it essentially positions the remaining elements one at a time rather than all at once.
Heres my code EDIT:
$('a.tag_filter').click(function(e){
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.spotlight_entry_container_grid').each(function(i){
var $entry = $(this);
var tagArray = [];
$('a.tag_filter', this).each(function(){
tagArray.push ($(this).attr('rel'));
});
if($.inArray(selectTag,tagArray) == -1){
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.spotlight_entry_container_grid:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
//we need to keep the entries in their columns.
//matching left values will do it. No need to animate left values.
if(leftPos == nextLeftPos){
$laterEntry.animate({ top: topPos});
}
});
});
}
});
});
Hopefully that makes sense
Any help would be appreciated!
I'm probably doing something crazy but I just can't spot it.
Thanks
in here
$('a.tag_filter', this).each(function(){
var curTag = $(this).attr('rel');
if(curTag == selectTag){
v++;
return false;
}
});
returning false inside of $().each() breaks the looping through each element in the wrapped set.
From the documentation
Returning 'false' from within the each
function completely stops the loop
through all of the elements (this is
like using a 'break' with a normal
loop). Returning 'true' from within
the loop skips to the next iteration
(this is like using a 'continue' with
a normal loop).
Also, I would recommend caching $(this) inside of each each() in a local variable for performance instead of referencing it several times.
EDIT:
After looking at the code further, I think the following should do it
$('a.tag_filter').click(function(e){
// prevent the default anchor behaviour
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.entry').each(function(i){
var $entry = $(this);
// get an array of the anchor tag rel attributes
var tagArray = [];
$('a.tag_filter', this).each(function() {
tagArray.push ($(this).attr('rel'));
});
// if we can't find the selected tag in the entries tags
if ($.inArray(selectTag,tagArray) == -1) {
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.entry:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
// for the first element, set top and left to the faded out element values
if (j == 0) {
$laterEntry.animate({ top: topPos, left: leftPos });
}
// for later elements in the loop, ste the values to the previous element values
else {
$laterEntry.animate({ top: nextTopPos, left: nextLeftPos });
}
});
});
}
});
});
You don't need to cache $(this), jQuery auto caches the this selector for function callbacks.

Categories

Resources