Strange behaviour with jquery .click() event - javascript

I think I'm trying to doing a simple thing but probably i miss something.
I've this little HTML
<div class="open"> OPEN</div>
with this simple CSS:
.open {
color: green;
}
.close {
color: red;
}
Now want to catch .click() events on the div but i want to select the with the class selector.
And for second i need to change the class and catch again a different .click() event based on the class. So I used this JQuery code:
$('.open').click(function() {
alert('open');
$(this).removeClass('open');
$(this).addClass('close');
$(this).text('CLOSE');
});
$('.close').click(function() {
alert('close');
$(this).removeClass('close');
$(this).addClass('open');
$(this).text('OPEN');
});
But this not work:
First click: right alert, class change, text change
Second click: wrong alert, class not change, text not change
You can check this jsfiddle: JsFiddle Example
Can you help me?
Thanks

You can simply do this with:
$('.open').click(function(){
var txt = $.trim(this.textContent) == "OPEN" ? "CLOSE" : "OPEN";
$(this).toggleClass('open').text(txt);
// $(this).toggleClass('open close').text(txt);
// use the commented line if you want to toggle the classes on each click.
});
.open {
color: green;
}
.close {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="open"> OPEN</div>

you need event delegation for this. since in the beginning, there is no div with the class close, the click handler is assigned to nothing.
just wrap your div
OPEN
and assign the click handler to the main div
$('.wrapper').on("click", ".open",function() {
alert('open');
$(this).removeClass('open');
$(this).addClass('close');
$(this).text('CLOSE');
});
$('.wrapper').on("click", ".close",function() {
alert('close');
$(this).removeClass('close');
$(this).addClass('open');
$(this).text('OPEN');
});
instead of $(this).removeClass('close'); $(this).addClass('open'); you shout consider to use $(this).toggleClass('open close');
https://jsfiddle.net/ezxe9ca8/2/

Try this,
$('.general').click(function() {
var status = $(this).attr('data-status');
if(status == 'open') {
alert('open');
$(this).removeClass('open');
$(this).addClass('close');
$(this).text('CLOSE');
$(this).attr('data-status', 'close');
} else if(status == 'close') {
alert('close');
$(this).removeClass('close');
$(this).addClass('open');
$(this).text('OPEN');
$(this).attr('data-status', 'open');
}
});
Then apply class to div
<div class="open general" data-status='open'> OPEN</div>

The problem is that the event handler bound to HTML element. In this case with the <div> No with the class close or open. For this reason, when you click on div only tigger the handler with alert("opne").
The solution is: Use only one handler and inside it put a 'if' stament. In pseudocode:
if class open
do someting
else if class close
do someting

Related

jQuery event listener fires before selector applied

I am trying to make a system that would require an admin to click a delete button twice before it fires the action. if he focusout of the button, it resets.
$(".unarmed").css("filter", "grayscale(1)").removeClass("armed").click(function(e) {
$(this).css("filter", "").removeClass("unarmed").addClass("armed");
}).mouseout(function() {
$(this).css("filter", "grayscale(1)").removeClass("armed").addClass("unarmed");
});
$("body").on("click", ".armed", function() {
alert("boom");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="unwait unarmed" src="plus.png">
I've seen jQuery event listener fires before selector applied? but adding e.stopPropagation() causes the second click to not fire.
when e.stopPropagation() is not in the code, it does fire the second click, but together with the first click (i think this means the problem is not with the second click selector)
here is a fiddle with e.stopPropagation():
https://jsfiddle.net/3jyr72t6/
also, if you have suggestion for making it prettier, i'm open for suggestions :D
#icecub answer as snippet:
$(document).ready(function() {
$(".unarmed").css("filter", "grayscale(1)");
$(".unarmed").click(function(e) {
if ($(this).hasClass("armed")) {
console.log("boom");
}
$(this).css("filter", "").removeClass("unarmed").addClass("armed");
}).mouseout(function() {
$(this).css("filter", "grayscale(1)").removeClass("armed").addClass("unarmed");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="unwait unarmed" src="https://kns.im/include/img/plus.png" style="width:50px">
You can always just use the jquery dblclick event. Jquery dblclick
$(document).on("dblclick",".btn-delete",function(){
console.log("DELETE");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn-delete">DELETE</button>
You can use a simple function to detect click outside the element .. See the next example
$("img.unwait").on("click" , function(e){
let $this = $(this);
if($this.hasClass("unarmed")){
$this.removeClass("unarmed").addClass("armed");
}else if($this.hasClass("armed")){
alert("BOOM");
$this.removeClass("armed").addClass("unarmed");
}
});
detect_click_out(".armed" , function(){
$(".armed").removeClass("armed").addClass("unarmed");
});
function detect_click_out(element_selector , action){
$(document).on('click',function(e){
if (!$(element_selector).is(e.target) // if the target of the click isn't the container...
&& $(element_selector).has(e.target).length === 0) // ... nor a descendant of the container
{action();} // run the action as a function
});
}
img{
width : 50px;
}
.unarmed{
filter : grayscale(1);
}
.armed{
filter : grayscale(0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="unwait unarmed" src="https://png.pngtree.com/element_our/sm/20180515/sm_5afb099d307d3.jpg">

Modify Script to Close Div

I've got a nice little show only one div at a time script working that I found at:
Random Snippets (second demo down) that looks like this:
function showonlyone(thechosenone) {
$('.newboxes').each(function(index) {
if ($(this).attr("id") == thechosenone) {
$(this).show(200);
}
else {
$(this).hide(600);
}
});
}
The only thing it doesn't do is close the div after you open it. Currently I have both divs set to display: none and would like to give the user the option to close them both when they are done looking.
Any idea's how to modify this?
You can have a click event that closes them when clicked:
$('.newboxes').click( function() {
$(this).hide(600);
});
You have to provide a button or something to the user to close the divs. Let's assume there is a button like this inside each div:
HTML
<div class="div-class">
<p>Box content</p>
<button class="close">Close</button>
</div>
jQuery
$('.close').on('click', function() {
$(this).closest('.div-class').hide();
});
add a condition about the visibility of the current item in the if statement:
function showonlyone(thechosenone) {
$('.newboxes').each(function(index) {
if ($(this).attr("id") == thechosenone && $(this).css("display") == "none") {
$(this).show(200);
}
else {
$(this).hide(600);
}
});
}

JQuery not removing class?

So, I am trying to create blocks that cycle through some colors. Each color is defined by a class, and I remove a certain class color, then add another class color when a block is clicked. Each segment of code looks like this:
//Function 1
$('.blue').click(function(){
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$('.green').click(function(){
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
When a block is clicked a first time, the color is changed. But when I click it again, the color does not change.
I added console.log statements to monitor in Console what was happening. As an example, when I click a box that has the blue class, it adds the green class, and the blue class is removed. But when I click the same box (that is now green) I expect the second function to run, and the box to change into a yellow color. However, what I can see through the console is that the first function is trying to run again.
I checked the HTML, and the classes do change.
My question is, why is function 1 triggered when the first box is no longer a member of the blue class? Should it not be calling function 2, since it is now a member of the green class?
The CodePen is here, I am actively working on it. I will mention here when the CodePen works.
**The CodePen now works, I used $(document).on('click', '.green') instead of $('.green).click() **
Thank you!
Since you want to change the event handlers based on changed selectors you need to use event delegation.
//Function 1
$(document).on('click', '.blue', function () {
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$(document).on('click', '.green', function () {
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
In your event registration, the selectors are evaluated only once when the page is loaded, any changes done after that to the classes will not affect the registered handlers.
Code Snippet Example
$(document).on('click', '.blue', function () {
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$(document).on('click', '.green', function () {
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
$(document).on('click', '.yellow', function () {
console.log("Yellow has been clicked");
$(this).addClass('blue');
$(this).removeClass('yellow');
});
$(document).on('click', '.red', function () {
console.log("Red has been clicked");
$(this).addClass('blue');
$(this).removeClass('red');
});
.block{
display: inline-block;
width: 200px;
height: 100px;
}
.green{
background-color: green;
}
.blue{
background-color: blue;
}
.yellow{
background-color: yellow;
}
.red{
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='block green'></div>
<div class='block blue'></div>
<div class='block yellow'></div>
<div class='block red'></div>
use on instead of click, because you're changing the class of your div, so you have to use .on() to get the click event bind when it changes the class
//Function 1
$(document).on('click', '.blue', function(){
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$(document).on('click', '.green', function(){
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
fiddle
What you are trying to do is this: http://jsfiddle.net/drxzLqrL/1/
$(document).ready(function(){
function foo($elm){
var color = $elm.data('color');
switch (color) {
case 'blue':
$elm.addClass('green')
.removeClass('blue')
.data('color', 'green');
break;
case 'green':
$elm.addClass('yellow')
.removeClass('green')
.data('color', 'yellow');
break;
case 'yellow':
$elm.addClass('red')
.removeClass('yellow')
.data('color', 'red');
break;
case 'red':
$elm.addClass('blue')
.removeClass('red')
.data('color', 'blue');
}
}
$('.block').on('click', function(e){
foo($(e.currentTarget));
});
});
Also use .on() instead of .click(), because you have to get the event when it changes the class and .on() provide you all the functionality of both .bind() and .live()
I hope it's help! :)
You want to use jQuery's .on() instead of the basic event binding:
https://api.jquery.com/on/
You just need to use toggleClass in this case.
FIDDLE
These clicks are binded to the elements only once, so they will not be there when you change the class. Instead, bind the click event to the 'block' class. You might also want to write this a bit more efficiently with switches or if/else.
$(document).ready(function(){
$('.block').click(function(){
if($(this).hasClass('blue'))
{
$(this).addClass('green').removeClass('blue');
}
else if($(this).hasClass('green'))
{
$(this).addClass('yellow').removeClass('green');
}
else if($(this).hasClass('yellow'))
{
$(this).addClass('red').removeClass('yellow');
}
else if($(this).hasClass('red'))
{
$(this).addClass('blue').removeClass('red');
}
$('.block').click(function(){
console.log("Block has been clicked");
});
});
});
You can view it working here:
http://codepen.io/anon/pen/pvGPyx
Lets do something different here. we'll use bind on the function - prior to executing it - to pass in an object parameter, and the scope of the function (this) being the instance handled within the anonymous function, or event delegate handler.
//Common Function
function ChangeState(state, evArg)
{
console.clear();
console.log("this: %o, state: %o, evArg: %o", this, state, evArg);
$(this).addClass(state.new);
$(this).removeClass(state.old);
}
//Function 1
$(document).on("click", ".blue", function(evArg){
ChangeState.bind(this,{"old":"blue","new":"yellow"}, evArg)();
});
$(document).on("click", ".yellow", function(evArg){
ChangeState.bind(this,{"old":"yellow","new":"red"}, evArg)();
});
$(document).on("click", ".red", function(evArg){
ChangeState.bind(this,{"old":"red","new":"green"}, evArg)();
});
$(document).on("click", ".green", function(evArg){
ChangeState.bind(this,{"old":"green","new":"blue"}, evArg)();
});
.block{
display: inline-block;
width: 200px;
height: 100px;
}
.green{
background-color: green;
}
.blue{
background-color: blue;
}
.yellow{
background-color: yellow;
}
.red{
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='block green'></div>
<div class='block blue'></div>
<div class='block yellow'></div>
<div class='block red'></div>

Temporarily disable button using jQuery

I would like to disable a button element without removing the listener, for example I have ths following code:
<input id="in" />
<button id="sub">Submit</button>
$('#sub').click(function (e) {
//Some actions
});
$($('#in').keyup(function (e) {
if (new Date($(this).val()) == 'Invalid Date') {
$(this).addClass('invalid');
$('#sub').addClass('disabled');
}
else {
$(this).removeClass('invalid');
$('#sub').removeClass('disabled');
}
});
I would like to unbind the button click listener, but if I'll use off() or unbind() I will have to 're-bind' it in the else clause.
Is there any better way of doing this?
How about disabling the button instead of adding a class?
HTML:
<button>Disable Me</button>
JS
$(function() {
$("button").click(function() {
alert("click!");
$(this).prop("disabled", true);
});
});
CSS
button[disabled] {
color: red;
}
Here is a jsFiddle to demonstrate.
use $('#sub').prop('disabled');

toggle- hide item when click outside of the div

I am using jquery's slidetoggle, want to learn how to make the showup class hide when click anywhere outside of the DIV.
thanks!
Online SAMPLE: http://jsfiddle.net/evGd6/
<div class="click">click me</div>
<div class="showup">something I want to show</div>​
$(document).ready(function(){
$('.click').click(function(){
$(".showup").slideToggle("fast");
});
});​
.showup {
width: 100px;
height: 100px;
background: red;
display:none;
}
.click {
cursor: pointer;
}
​
Stop event propagation from within the .showup area:
$(document).on("click", function () {
$(".showup").hide();
});
Then prevent those clicks on .showup from bubbling up to the document:
$(".showup").on("click", function (event) {
event.stopPropagation();
});
Any click event that reaches the document will result in the .showup element being hidden. Any click events that start from within .showup will be prevented from proceeding any further up the DOM tree, and thus will never reach the document.
You will also need to stop any clicks on your button from traveling up to the document as well:
$(".click").on("click", function (event) {
event.stopPropagation();
$(".showup").slideToggle("fast");
});
Otherwise that click event will bubble up to the document and result in the hiding of .showup immediately.
Demo: http://jsfiddle.net/evGd6/2/
If you still want to record clicks on .showup panel (lets say you want it to be more then a simple informative panel), calling event.stopPropagation() on clicking it will make that panel untouchable/useless. Use event.cancelBubble = true instead and will let the event occur on .showup childs.
$('.click').click(function(){
$(".showup").toggle();
});
$(".showup").on("click", function (/*nothing here*/) {
event.cancelBubble = true
});
$(document).on("click", function () {
$(".showup").hide();
});

Categories

Resources