For loop runs once, 2/3 of the way (javascript) - javascript

function clearObjects() {
var co = document.getElementsByClassName("clearable");
var i;
alert("function runs");
for (i = 0; i < co.length; i++) {
alert("for loop runs 1/3");
alert("for loop runs 2/3, time to erase");
co[i].style.backgroundColor = "#FFFFFF";
alert("for loop runs 1, erased 1");
};
};
clearObjects();
This function that I has here is suppose to change the color of all divs with the class of clearable to a background color of white, where they are "Erased." The function runs inside of my other code, but my issue is that the for loop stops running when it gets to:
co[i].style.backgroundColor = "#FFFFFF";
I put alerts in there to see what parts of the function run, and the final alert "for loop runs 1, erased 1" does not alert, and the for loop does not run again. I have looked and could not find a problem similar to mine. Does anyone know what I am doing wrong? I will post all of my code if neccessary. Thanks!

I fixed my problem by setting the visibility to hidden instead of background to white, and by setting the class of the new divs with jquery's attr() function instead of what I had. It works perfectly now, thanks for all the input!

The issue you were running into is that you were attempting to set the class of each drawn object in CSS. The change to fix that is changing this:
var div = $('<div>').css({
'class': 'clearable'
});
To this:
var div = $('<div>').css({
...
}).addClass('clearable');
You can also remove the element easily by using co[i].parentNode.removeChild(co[i]) instead of changing the background color (frees up memory). I've reversed the direction of the loop in my example because you're dealing with removing elements (and that shifts the array one element backwards causing you to skip an item each time if going forwards).
See my code pen: http://codepen.io/anon/pen/BNYRWE

Related

Trigger a fade when swapping between classes using jQuery

I have following code working so far: JSFIDDLE DEMO
The relevant JS is here:
// Define classes & background element.
var classes = ['bg1','bg2','bg3','bg4'],
$bg = document.getElementById('blah');
// On first run:
$bg.className = sessionStorage.getItem('currentClass') || classes[0];
// On button click:
$('.swapper').mousedown(function () {
// (1) Get current class of background element,
// find its index in "classes" Array.
var currentClassIndex = classes.indexOf($bg.className);
// (2) Get new class from list.
var nextClass = classes[(currentClassIndex + 1)%classes.length];
// (3) Assign new class to background element.
$bg.className = nextClass;
// (4) Save new class in sessionStorage.
sessionStorage.setItem('currentClass', nextClass);
});
For my purposes, this functionally working great -- I can click a single button to continually swap between those four classes while also storing the current class to sessionStorage, so that when I click links on my website, the currentClass is loaded right away. (Note: on my website the setup is the same, but the classes bg1, bg2, bg3, and bg4 contain background images.)
What I'd like it to do:
When swapping from one class to another, I'd like it to do a quick/short cross-fade. Right now it just snaps from one class/background to another.
My thinking was: is there a way I can trigger a CSS class transition or animation that contains the fade, perhaps as a parent class? I know there's a jQuery fade function, but I haven't been able to get it working with my setup so that it triggers on mouseClick.
Here's an updated jsfiddle based on your comment where you said you've sort of having it work.
I've added the timeout functions
setTimeout(function(){$bg.className = nextClass}, 500);
setTimeout(function(){$($bg).fadeIn(500)}, 500)
The first timeout makes it so that the image is swapped right after the first image fades out. The second timeout gives it a bit of time to load in so it's not so jittery.
You can play with the }, 500); number to get it timed just like you want, 500 is half a second, 1000 is a second etc.

Javascript cannot unhide element after cloning?

I'm working on something where multiple functions will add various Event listeners to an initially hidden div, let's just call it secretBlock. Only one will ever be active at any given point, but all said functions will manipulate it by:
First cloning sercetBlock to ensure no previous listeners are still attached
Then setting the display to flex
HTML:
<div id="secretBlock" hidden>Secret</div>
JavaScript:
function exampleFuction() {
var secretBlock = document.getElementById('secretBlock');
var secretClone = secretBlock.cloneNode(true);
secretBlock.parentNode.replaceChild(secretClone, secretBlock);
secretBlock.style.display = 'flex';
....
}
but the last part, setting the display, is not firing.
I assumed this had something to do with async-ness, but
setTimeout(function(){ secretBlock.style.display = 'flex' }, 999);
also had no effect.
However, one of the functions appends the div inside of another div right after setting the display, causing it to fire properly:
secretBlock.parentNode.replaceChild(secretClone, secretBlock);
secretBlock.style.display = 'flex';
otherDiv.appendChild(secretBlock);
After a bit of testing, I found out it doesn't matter when I set the display (now vs later) or where it is in the code, as long as secretBlock gets appended to another div, the display change will register, otherwise staying hidden.
.......which sorta left me clueless as to what's going on, any insight would thus be much appreciated~~
Was a reference issue.
After .replaceChild() replaces secretBlock, the initial reference:
var secretBlock = document.getElementById('secretBlock')
becomes obsolete as it still points to the old, original element which is not apart of the html document anymore. Thus you need to redirect the reference to the cloned element:
secretBlock.parentNode.replaceChild(secretClone, secretBlock);
secretBlock = document.getElementById('secretBlock');
secretBlock.style.display = 'flex';
Thanks Dr.Molle!

Random color border (Javascript) around database entries (thumbnails)

at the moment I'm working on a website that is meant to be my portfolio so I wanted it to be a challenge.
The section where I show my work is coded with PHP and is connected to a database. With a WHILE loop it adds all the database records on my website.
For this site I have decided to use Javascript for the first time, to make it more challenging and to learn this as well.
What I want is a border around every database record the PHP WHILE loop adds, which is only shown when hovered over and changes color (fixed array of colors) every time you hover over the thumbnail.
This is the code I have so far:
function loaded() {
var colors = ["#FC3E6B","#24FF00","#0087F9","#F9F900"];
var images = document.getElementById("thumbnails").getElementsByTagName("div");
console.log(images);
for (var i = 0; i < images.length; i++) {
var rand = Math.floor(Math.random()*colors.length);
images[i].style.borderStyle = 'solid';
images[i].style.borderWidth = '1px';
images[i].style.borderColor = 'transparent';
$(images[i]).hover(function(){
console.log('hovering over');
images[i].style.borderColor = colors[rand];
}, function(){
console.log('hovering out');
images[i].style.borderColor = 'transparent';
});
};
};
My problem now is that it doesn't work, or partially. This code only applies on the first entry the WHILE loop adds. In the console I can see that the "console.log(images)" only returns the first entry.
Another problem is that it also returns an error:
images[i] is undefined
images[i].style.borderColor = colors[rand];
These are the 2 things I'm struggling with at the moment. It might very well be beginner/easy mistakes since it's my first time working with Javascript.
If there is anything I forgot to mention or you need to know, let me know.
I'm looking forward to a reply.
If I understand you right you should have an HTML page (generated with PHP) that looks like:
<div id="thumbnails">
<img src="..." />
<img src="..." />
<img src="..." />
...
</div>
And if you hover one of the images you want to add a border to this an remove the border if the mouse leaves the image. I assume you are using jQuery, so you could add each image a class e.g. <img class="record" src="..." /> and try the following javascript:
$(function() {
var colors = ["#FC3E6B","#24FF00","#0087F9","#F9F900"];
$('.record').hover(
function() {
var rand = Math.floor(Math.random()*colors.length);
$(this).css('border-style', 'solid');
$(this).css('border-width', '1px');
$(this).css('border-color', colors[rand]);
},
function() {
$(this).css('border-style', 'none');
}
);
}).call(this);
Each time the cursor enters an element (in your case an image) this will get a border, if the cursor leavs it the border will be removed.
Ok, first off: (colors.length - 1) is where you want to go, an array of length 3, has 2 as highest key (0-indexed!)
Second: can you post the actual HTML, or better still: get a jsfiddle up, so we can actually ammend your code, or fork your jsfiddle?
Third: I notice you're using jQuery, have you tried using $('#thumbnails').find('div'); to get your images array? what do you get then?
In case anyone reading this wonders, the reason the original example didn't work is because it is creating a closure. The inner function has access to the variables created in the outer function, but it gets the value of variables when the outer function returns.
In this case, when the code:
images[i].style.borderColor = colors[rand];
executed, the value of i would have been 4, which is outside the range, for each image.
See this for an explanation:
JavaScript closure inside loops – simple practical example

While loop in jquery of dynamic id and class

I have have multiple divs' with similar code within it, but also has a unique id within the main div that calls a toggleClass & slideToggle function. I'm trying to create a loop so that I do not have to write similar code for each element.
--- working code --- (where numeric value after the id would change)
$('#er1').click(function() {
$('#er1').toggleClass('but-extra-on');
$('#cr1').toggleClass('but-closerow-on');
$('#er1').next('div').slideToggle('slow');
return false;
});
-- not working code -- (I want to have functions for the click of #er1, #er2, #er3 etc.)
var count = 1;
while (count < 10){
var curER = 'er'+count;
var curCR = 'cr'+count;
$('#'+curER).click(function() {
$('#'+curER).toggleClass('but-extra-on');
$('#'+curCR).toggleClass('but-closerow-on');
$('#'+curER).next('div').slideToggle('slow');
});
count++;
}
* for some reason, when I use the while code, whenever I click #er1, #er2, #er3 etc.. only the event for #er9 toggles.
You can solve this problem, by using the $(this) selector for the one that you are clicking, and attaching an html data attribute to the div, specifying the other div that you want to change when you click it and selecting the other one with that... make sense.. probably not? Check out Solution 1 below.
The second solution is to use jQuery Event Data to pass the count variable into the event listener.
Solution 1: http://jsfiddle.net/Es4QW/8/ (this bloats your html a bit)
Solution 2: http://jsfiddle.net/CoryDanielson/Es4QW/23/
I believe the second solution is slightly more efficient, because you have slightly less HTML code, and the $(this) object is slightly smaller. Creating the map and passing it as event data, I believe, is less intensive... but... realistically... there's no difference... the second solution has cleaner HTML code, so you should use that.
Solution 3 w/ .slideToggle(): http://jsfiddle.net/CoryDanielson/Es4QW/24/
Edit: Updated solutions by passing in the selected elements instead of the selectors. Now each click event will not do a DOM lookup as it did before.
I've run into this problem before. I fixed it by extracting the event listener code into its own function like so:
for (var i = 1; i < 10; i++) {
attachClickEvent('er'+i, 'cr'+i);
)
function attachClickEvent(cr, er)
{
$('#'+er).click(function() {
$(this).toggleClass('but-extra-on');
$('#'+cr).toggleClass('but-closerow-on');
$(this).next('div').slideToggle('slow');
});
}

Can't highlight row for dynamically created GridView from JavaScript

It use to be easy to do this, but this was my first time generating the GridView dynamically. Each GridView cell has its own CSS Styling when created. In RowDataBound event I set up the highlighting as usual:
e.Row.Attributes.Add("onmouseover", "this.style.cursor='pointer';HilightRow(this);")
e.Row.Attributes.Add("onmouseout", "HilightRow(this);")
On the script side I have the following:
var curSelRow = null;
function HilightRow(row) {
var selRow = row;
var i;
.
.
if (selRow != null) {
curSelRow = selRow;
curSelRow.style.backgroundColor = '#FFEEC2';
}
}
I've traced this in the script and it works fine, there are no errors and when I do a watch on the row in question, it does correctly show the correct background color value (i.e. #FFEEC2), however, the hover does not change the color of the row. I'm puzzled. Not sure why this is happening and as I said, I've done this many times before without a problem but the gridviews were not dynamic in the past.
I'm not sure if you've shown all your code, but it appears that both the over and out function are setting the same bgcolor (#FFEEC2).
Both onmouseover and onmouseout are calling HilightRow(this). Does the initial onmouseover set the bgcolor?
A nicer solution I think is adding a class to the row.
Like class="Hilightrow".
And avoid script in the html-elements and separate structure from behaviour.
var hiliclass = "Hilightrow";
var trhilight = document.getElementById("mytable").getElementsByTagName("tr");
var len = trhilight.length;
for(var i=0;i<len;i++) {
if(trhilight[i].className == hiliclass) {
trhilight[i].onmouseover = function() {
trhilight[i].style.backgroundColor = "red";
}
....
}
}
And have the script inside a function and call it inside window.onload or
use a self-invoking function like this:
function highlightrows() {
..// my code
}();
I figured out the problem finally. What you have to do before you set the highlighting is to remove the currently applied Style to the row by setting the curSelRow.cells[i].style.backgroundColor = ''. Now you can highlight the row by using curSelRow.style.backgroundColor = '#FFEEC2', which will set the row to the highlight value.
In addition, you must save each cell's own style before you reset the values and restore each cells value when the cursor leaves that row. Otherwise you'll get white for each row that you hover over. Again, remember to reset the style for the highlighted row before you setting each cell's style to what it was originally.
What a pain!

Categories

Resources