Javascript setInterval() creates a weird outcome(?) - javascript

I encountered a weird problem with the setInterval method that I really don't get.
So I created a website with 25 boxes and the idea was that clicking on any box would change the backgroundColor of that box for half a second after which it would return to the original color. After that animation finished the next box would change its color for half a second and then go back to the original state. This cycle would continue until it reached the last box.
The code I wrote for that is this:
window.onload = function() {
var box = document.getElementsByClassName("box");
for (i = 0; i < box.length; i++) {
box[i].onclick = starter;
}
}
function starter(eo) {
var box = eo.target;
var counter = eo.target.id;
box.style.backgroundColor = "#1A237E";
setTimeout(cont, 500, counter);
}
function cont(counter) {
var box = document.getElementsByClassName("box");
box[counter].style.backgroundColor = "white";
counter++;
box[counter].style.backgroundColor = "#1A237E";
if (counter < box.length) {
setInterval(cont, 500, counter);
}
}
(All the boxes have the class "box" and are labelled with IDs from 0 to 24)
The code actually executes and is technically working. The weird thing is that after about 8 iterations several boxes start to flash up simultaneously(different boxes for each iteration of the cont() function) and the whole code slows down enormously. This happens regardless of the starting position.
I have no idea where I made a mistake in the code, can someone explain to me white it happens?
Many thanks in advance :)

Related

Javascript - Trying to create a grid, but can only get rows. I am not sure what to do next

so I am trying to create a etch-a-sketch and I need to generate multiple divs (i.e. little squares) based on the users input. So for instance the option is how many pixels do you want the grid size to be from 1 - 50 and based on the answer (say 30) I need to make a grid with that many squares on each side. The issue is that I can only get that many squares as a row at the top and not as a grid. Linked is my code and also shown is my javascript code which is the one giving me issues. The HTML/CSS are mostly just styling, but they are shown in the link. I am not sure what I am doing wrong because I am using someone else's code as reference and it seems to work for them, but not for me.
https://codepen.io/faar23/pen/qjZgQY
$(document).ready(function(){
/*for (var i = 0; i < 24; i ++) {
$('#workspace').append('<div class = "row"></div>');
$('.row').height(27);
};*/
/*for now i am going to leave the above code commented out but what it
does is instantly creates 24 boxes on the workspace
and without this, the space is empty. I am commenting it out to see if the
.height function will wor down below...doesnt seem to*/
/*the above loop generates 24 divs dynamically without having to copy paste
in html. the .height sets the height of the divs.
the width is set in the css under myId. this was done using this tutorial
https://www.youtube.com/watch?v=dtgx_twX-a4 + inspecting
the elements on this project https://beachfern.github.io/sketchpad/*/
$('#mainButton').mouseenter(function(){
$('#mainButton').addClass('highlight');
});
$('#mainButton').mouseleave(function(){
$('#mainButton').removeClass('highlight');
});
/*the above code makes the main start button change color when the mouse
enters it*/
$('.buttonhide').hide();
$('#mainButton').click(function(){
$('.buttonhide').show();
});
/*the above code hides the rest of the buttons until the main button is
clicked, then all the buttons show themselves*/
$('#mainButton').on('click', function(){
var workspaceSize = prompt("How many boxes should make up the canvas? (1
to 50)", "24");
/*i am going to use this user's way and see if that works better for me
https://stackoverflow.com/questions/25518243/creating-div-grid-with-
jquery-for-loop*/
if(workspaceSize > 0 && workspaceSize <= 50){
$('#workspace').empty();
for (var i = 0; i < workspaceSize; i++){
$('#workspace').append('<div class = "row"></div>');
};
for (var x = 0; x < workspaceSize; x++){
$('.row').append('<div class = "column"></div>');
};
$('.row').height(700 / workspaceSize);
$('.column').height(700 / workspaceSize);
$('.column').width(700 / workspaceSize);
}; /*very imp closing bracket. shit doesnt work without it*/
});
});
You need to nest the two for loops, so that for each row it creates the columns.
This might work, or lead you in the right direction:
for(var i = 0; i < workspaceSize; i++){
$('#workspace').append('<div class="row" id=row'+i+'></div>');
for(var j = 0; j < workspaceSize; j++){
$('#row'+i).append('<div class="column"></div>')
}
}

Ext setLoading(true,true) being called too late?

I have a grid with a good amount of data which the user can filter or show/hide groups of columns by using combo boxes. Some of the column switches take a long time to load and I want to call setLoading(true,true) on the grid or the combobox to show the user that the browser is working.
I have a listener function that is called when the user makes a selection on the combo box. I call combo.setLoading(true,true) before starting any of the code that takes a while to execute. Then I call combo.setLoading(false,false) at the very bottom of the function.
The loading only shows up for a split second after the code between the two setLoading calls has executed. If I take out the call to remove the loading icon, the icon still only shows up after the code is executed.
Anyone have an idea what is happening? This seems very odd to me.
categorycomboselect: function(combo, records){
combo.setLoading(true,true);
var panel = combo.up('panel');
console.log(panel);
var category = records[0].data.name;
var grid = Ext.ComponentQuery.query('grid')[1];
Ext.suspendLayouts();
grid.suspendedLayout=true;
var columns = grid.columns;//.getView().getGridColumns();
//slow code that shows/hides columns
grid.suspendedLayout=false;
Ext.resumeLayouts(true);
combo.setLoading(false,false);
},
UPDATE
Here is my code with Trimboli's suggestion, it still isn't working. I'm showing/hiding the columns based on a string in their ID. I did it this way because the categories I want to show/hide the columns on are dynamic and the columns are dynamic.
categorycomboselect: function(combo, records){
combo.setLoading(true,true);
setTimeout( function(){
var panel = combo.up('panel');
var category = records[0].data.name;
var grid = Ext.ComponentQuery.query('grid')[1];
Ext.suspendLayouts();
grid.suspendedLayout=true;
var columns = grid.columns;
if(category=='All grade items'){
for(var i = 0; i< columns.length; i++){
columns[i].setVisible(true);
}
}else{
for(var i = 0; i< columns.length; i++){
columns[i].hide();//setVisible(false);
if(!(typeof columns[i].itemId ==='undefined')){
if((columns[i].itemId).indexOf(category)>=0){
columns[i].show();
}
}
}
}
grid.suspendedLayout=false;
Ext.resumeLayouts(true);
combo.setLoading(false,false);
},1);
},
Also, I wasnt sure if
Ext.suspendLayouts();
grid.suspendedLayout=true;
do the same thing or not. And if not, which is better.
What you're essentially doing is this:
showMask();
for (i = 0; i < 10000000; ++i) {
// busy loop
}
hideMask();
If you show/hide a mask without giving the browser a "break" for it to update the DOM, you won't see anything because it all gets flushed out at the end once you relinquish control back to the browser.
If you wanted to let the mask actually show, you need to give a slight delay before continuing on with your busy loop:
showMask();
setTimeout(function() {
// Busy stuff
hideMask();
}, 1);

Shift + Click to Select a Range of Checkboxes

I have large tables being generated and each row has a checkbox, class "chcktbl".
In the table header, there is a Select All checkbox, class "chckHead".
The select/deselect all function works fine, as does the count of selected charts I have displayed in the table heading.
The function to enable shift+click capability to select a range of checkboxes also works, but in its current format, only selects 10 checkboxes before generating an error message in a popup window:
"Stop running this script? A script on this page is causing your web browser to run slowly. If it continues to run, your computer might become unresponsive."
<script type=text/javascript>
//select all button
$('#chckHead').click(function() {
if (this.checked === false) {
$('.chcktbl:checked').attr('checked', false);
}
else {
$('.chcktbl:not(:checked)').attr('checked', true);
}
countSelected();
});
//count number of boxes checked
function countSelected() {
var numCharts = $('input.chcktbl:checked').length;
$('#numCharts').html(numCharts);
}
//SHIFT+Click to select a range of checkboxes:
// this variable stores the most recently clicked checkbox
// it is used for shift-clicks
var lastClickedBox = 0;
// the checkbox functionality is default to the browser
$('.chcktbl').click(function(event) {
var clickedBox = $('.chcktbl').index(event.target);
if(event.shiftKey) {
setCheckboxes(lastClickedBox, clickedBox);
};
lastClickedBox = clickedBox;
countSelected();
});
// sets all the checkboxes between the specified indices to true
function setCheckboxes(end, start) {
if(start > end) {
var temp = start;
start = end;
end = temp;
};
for(var i = start; i < end; i++) {
$('.chcktbl').eq(i).prop('checked', true);
};
countSelected();
};
</script>
This is a really common feature for selecting a range of items with one click, but I can't find an efficient way to do it. If anyone knows a better way of approaching this or can spot some inefficiency in the code then please let me know.
How about using jquery nextUntil?
I didn't actually test this but this should give you the basic idea and it removes the for loop. I created similar functionality to this before using nextUntil/prevUntil and never got an unresponsive page.
function setCheckboxes(end, start) {
if(start > end) {
var temp = start;
start = end;
end = temp;
};
$('.chcktbl').eq(start).nextUntil(':eq('+(end+1)+')').add().prop('checked', true);
countSelected();
};
I tried you code and it worked well for me. You might want to try this jquery plugin
https://gist.github.com/DelvarWorld/3784055

detecting a div's position based on it's attaribute

I have three divs and I want to execute a command on a div that happens to be on top of the other divs in a container without referencing it's name or id.I am randomizing the position of the divs and I basically want the div whose height is equal to 10px to change it's color attribute to red when a specific number is generated, whilst the other divs maintain their default color. I have tried the following but I can't think of any way to do this without using the div's id.
var current = 0;
current++;
var topArrtcard = document.getElementById("card-answer");
var topArrtcard1 = document.getElementById("card-answer1");
var topArrtcard2 = document.getElementById("card-answer2");
if(current === 0 ){
topArrtcard.style.color = "red"; // is it possible not use the id in order to make the change
topArrtcard1.style.color = " #996600";
topArrtcard2.style.color = " #996600";
}else if(current === 1 )
{
topArrtcard.style.color = "#996600";
topArrtcard1.style.color = "red";
topArrtcard2.style.color = " #996600";
}else if(current === 2){
topArrtcard.style.color = "#996600";
topArrtcard1.style.color = " #996600";
topArrtcard2.style.color = "red";
}else {
topArrtcard.style.color = "#996600";
topArrtcard1.style.color = " #996600";
topArrtcard2.style.color = "#996600";
}
the variable current increments by 1 each time the page is loaded. I hope this is clear. Thank you in advance.
If you are not opposed to using jQuery (and why would you be? In many ways it's simpler than javascript with much less to type)...
I cannot see from your code (at this moment) what will trigger an event that you can use to do the testing that you want.
However, if something does happen to the DIV, then perhaps you can use that event to make the changes you want. You would reference the changed DIV as this.
Here is an example that looks somewhat similar

Flipping 3 text with animation

I have a small requirement. I have a div with three child divs with text. On load the first text will be visible. After 3 seconds the first one hides and second one is visible. After another 3 seconds the second one hides and third one is visible. This continues.
Currently I do not have any animation on the hide of one span and show of another. So it looks kind of murky. White I want is to show some kind of animation as it happens on the windows 8 tiles. Like the text that hides should slide up and disappear and the text that is to be shown should slide in from bottom. the animation should give the user a smooth experience.
I am not using any animation library. Is this possible through javascript / css ? Below is my code. Any idea would be useful.
HTML :
<div class="dataflipping">
<div class="first">FIRST TEXT</div>
<div class="second">SECOND TEXT</div>
<div class="third">THIRD TEXT</div>
</div>
JavaScript:
var srcElement = document.getElementsByClassName("dataflipping");
var elementChld = srcElement.getElementsByTagName("div");
var elementArr = [];
for (counter === 0; counter < elementChld.length; counter++) {
elementArr.push(elementChld[counter]);
}
var elementCount = elementArray.length;
// Set all except first one to hidden initially
for (counter = 1; counter < elementCount; counter++) {
var ele = elementArray[counter];
ele.style.display = "none";
}
counter = 0;
setInterval(function () {
counter++;
var prevElement = null;
var curElement = null;
if (counter === 1) {
var prevElement = elementArr[elementCount - 1];
}
else {
prevElement = elementArr[counter - 2];
}
curElement = elementArr[counter - 1];
prevElement.style.display = "none";
curElement.style.display = "block";
if (counter === elementCount) {
counter = 0;
}
}, 3000);
Girija
IF I understood well. I think easier way is to use MODULO, I wrote something like this:
elementArr[counter%elementCount]
http://jsfiddle.net/t3N4A/
I think you just need to try make position:absolute; and like i change opacity you should change it left/top position, change frequency of setInterval function to make it smoother and make it disappear where u want to. Hope that helped a little.

Categories

Resources