Can someone explain why the following fiddle is failing.
I'm simply removing the first square element and appending a new square element on button click.
I'm going to start pulling my hair out soon. It seems like it works as expected on the first button click, but then weird things start to happen on consecutive clicks.
$('.click-me').on('click', function() {
let _this = $(this),
_main = $('.main');
// Mark the first square for removal and update the classes of the other squares to replace it.
_main.children().each(function() {
let _square = $(this);
if ( _square.hasClass('square1') )
_square.removeClass('square1').addClass('remove');
if ( _square.hasClass('square2') )
_square.removeClass('square2').addClass('square1');
if ( _square.hasClass('square3') )
_square.removeClass('square3').addClass('square2');
if ( _square.hasClass('square4') )
_square.removeClass('square4').addClass('sqaure3');
if ( _square.hasClass('square5') )
_square.removeClass('square5').addClass('sqaure4');
});
// Remove square1 and append a new square5.
_main.find('.remove').remove();
_main.append('<span ></span>');
});
.main {
position: relative;
display: flex;
margin-top: 20px;
}
.main span {
width: 35px;
height: 35px;
background-color: #2e852e;
border: 1px solid #000;
}
.main .square1,
.main .square5 {
background-color: #a5a551;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button >Click Me!</button>
<div >
<span ></span>
<span ></span>
<span ></span>
<span ></span>
<span ></span>
</div>
CodePudding user response:
- It'll be much easier to use
data
attribute to save the number .. likedata-number="1"
and the selector will be like[data-number="1"]
- Then no need for
square1,square2...
even no need foradd/removeClass
at all - The arrange of code make difference .. remove the first square before you decrease the number by one
This is how it should looks like .. Click the button once until you get the action and to understand whats doing on
$(document).on('click', '.click-me:not(.running)', function() {
let _this = $(this),
_main = $('.main');
// add Class running
_this.addClass("running");
// Remove [data-number="1"] and append a new square with [data-number="5"].
_main.find('.square[data-number="1"]').remove();
console.log("First square removed")
// decrease number by 1
setTimeout(function(){
$(".square").each(function(){
let number = $(this).attr("data-number");
$(this).attr("data-number" , number - 1);
});
console.log("Decrease number by one so the second square will be first and background will change");
} , 2000);
// append the new square
setTimeout(function(){
_main.append('<span data-number="5"></span>');
console.log("The new sqaure added");
// remove Class running
_this.removeClass("running");
} , 4000);
});
$(document).on('click', '.click-me.running', function() {
console.log("Action running");
});
.main {
position: relative;
display: flex;
margin-top: 20px;
transition : 0.4s;
}
.main span {
width: 35px;
height: 35px;
background-color: #2e852e;
border: 1px solid #000;
}
.square[data-number="1"],
.square[data-number="5"] {
background-color: #a5a551;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button >Click Me!</button>
<div >
<span data-number="1"></span>
<span data-number="2"></span>
<span data-number="3"></span>
<span data-number="4"></span>
<span data-number="5"></span>
</div>
I added setTimeout
to give the code a little bit of time to show the action.. because without the setTimeout
the code will run but Unnoticeable
Additional: I added class running
to the button to prevent multiple clicks while the action is running
CodePudding user response:
I believe the objective is to remove the first square and move the remaining squares into the position that precedes it and add a new square to the end. In the example provided each square has a different background color assigned by class which never changes -- this way it is easy to see that the actual squares are moving into their correct positions. The other classes ".b1" to ".b5"
will be reassigned to each square on every click of the button. As the first one is removed, it's replacement is immediately placed at the end. The new square will be assigned ".b5"
and a color class determined by an external counter and an array. Also, each square has the CSS pseudo-element ::before { content: attr(class) }
to show classes as text content.
The trick is to count every click (that's done with count
) and every significant iteration (that's done with the first parameter of .each(i)
. Set some arrays as references (positions
array for classes ".b1" to ".b5"
and rainbow
array for color classes).
const rainbow = ['green', 'blue', 'red', 'gold', 'violet'];
const positions = ['b1', 'b2', 'b3', 'b4', 'b5'];
let count = 0;
$('button').on('click', function() {
$('b').each(function(i, e) {
if (i === 0) {
e.remove();
$('main').append(`<b class='${rainbow[count]} b5'></b>`);
} else {
let current = positions[i];
let previous = positions[i - 1];
$(e).addClass(previous);
$(e).removeClass(current);
}
});
count ;
if (count > 4) count = 0;
});
main {
display: flex;
margin-top: 20px;
}
b {
display: inline-block;
width: 35px;
height: 35px;
padding: 10px;
border: 1px solid #000;
text-align: center;
}
b::before {
content: attr(class);
}
.green {
background: green;
color: white
}
.blue {
background: blue;
color: gold;
}
.red {
background: red;
color: white;
}
.gold {
background: gold;
color: blue;
}
.violet {
background: violet;
color: black;
}
<button>Click Me!</button>
<main>
<b ></b>
<b ></b>
<b ></b>
<b ></b>
<b ></b>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
CodePudding user response:
Well folks thanks to everyone who answered but the simple answer was a 2 letter change, literally:
if ( _square.hasClass('square4') )
_square.removeClass('square4').addClass('sqaure3');
if ( _square.hasClass('square5') )
_square.removeClass('square5').addClass('sqaure4');
The genius in me has put 'sqaure3'
and 'sqaure4'
in the if
statements above. Simply fixing those to the expected 'square3'
and 'square4'
, respectively, solves the problem.
PS1: I'd like to mention that my jsFiddle is definitely not formatted with max efficiency in mind (as has been proven by the other answers on here). It was just a quick sample I put together to try and demonstrate a layout problem I was having (nothing to do with this question) but ended up with a different problem due to my spelling mistake.
PS2: I personally think this question is a waste of time to go through for anyone else but Stackoverflow is being silly and won't let me delete the question. Sorry about that.