Two click events for the same element - javascript

I have a situation where I have a click event attached to an element's onClick attribute and also a click event that fires on any element with a specific class. The element's onClick event causes a panel on the page to close. The class's onClick event causes the page to scroll to an element lower on the page.
The problem is that both seem to fire at the same time causing the page to scroll beyond the targeted element. Here is a code sample:
$(document).ready(function() {
$('.proceed').on("click", function() {
$('html, body').animate({
scrollTop: $(this).closest('.item-section').next().offset().top
}, 2000);
})
});
function openPanel() {
var rb1 = $("#radioButton1").is(':checked');
alert("Clicked");
$('#containerBox1').toggle(rb1);
}
.item-section {
height: 500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="">
<div class="item-section">
<p>Choose a food</p>
<input type="radio" id="radioButton1" name="food" value="pizza" onclick="openPanel()">Pizza<br>
<div id="containerBox1" style="display: none;">
<p>Choose a topping</p>
<input type="radio" name="topping" value="pepperoni">Pepperoni<br>
<input type="radio" name="topping" value="vegetarian">Vegetarian<br>
<button class="proceed">Proceed to next section</button>
</div>
<input type="radio" name="food" value="burger" class="proceed">Burger<br>
<input type="radio" name="food" value="fish" class="proceed">Fish
</div>
<div class="item-section">
<p>Drink selection would be here</p>
</div>
</form>
Does anyone know how to fix this keeping in mind that my real code is much larger than the sample provided and has more classes and buttons.

You could try
extract the .proceed click handler to a named function
call that named function from the .proceed click handler
in openPanel, do whatever the function needs to do, then call the scroll handler, then call stopPropagation on the event
In other words, don't allow two click handlers to fire for your radio button, but have one click handler that does both tasks and then stops propagation.

You don't need two onclick events. Just process the one for .proceed and check to see if rb1 is checked.
$(document).ready(function() {
$('.proceed').on("click", function() {
var rb1 = $("#radioButton1").is(':checked');
if( rb1 ) {
alert("Clicked");
$('#containerBox1').toggle(rb1);
}
$('html, body').animate({
scrollTop: $(this).closest('.item-section').next().offset().top
}, 2000);
})
});

Related

event.target triggers input and label elements in js

I am working on a form and in that I am using radio buttons but because of the styling issues i just hides them by display: none property. And done all the styling on its corresponding label element.
<form>
<div class="radio-input">
<input type="radio" style="display:none;" name="color" value="green" id="g2" />
<label class="square-box" for="g2"></label>
<input type="radio" style="display:none;" name="color" value="blue" id="b2" />
<label class="square-box not-allowed" for="b2"></label>
</div>
</form>
Now I have attached and event listener on that parent div and waiting for an event to bubble. But when i click label, event.target returns both label and input element. So that creates a problem.
document
.querySelector(".radio-input")
.addEventListener("click", function (event) {
if (event.target.classList.contains("not-allowed")) {
// do something...
} else {
// do something...
}
};
So in this if label has not-allowed class i wanna do some operation but because event.target returns both the elements, addeventlistener runs twice and fails the code(basically if condition).
So the two possible solutions might be
just ignore input elements by adding a condition in the if
event.target somehow don't return the input element
whatever the solution be please tell me!
As this answer, you can stop default behaviour of the addEventListener like this:
document
.querySelector(".radio-input")
.addEventListener("click", function (event) {
event.preventDefault(); // adding this to your code
if (event.target.classList.contains("not-allowed")) {
console.log("not allowed");
} else {
console.log("allowed");
}
});
You can also ignore input element:
document
.querySelector(".radio-input")
.addEventListener("click", function (event) {
if(event.target.nodeName === 'INPUT')return; // if it's input, just return
if (event.target.classList.contains("not-allowed")) {
// do something...
} else {
// do something...
}
};
As mentioned above preventDefault() or possibly stopimmediatepropagation()

How do I make DOM/event listeners aware of newly appended nodes?

TL;DR:
I use $(..).append(node), but newly added nodes are not considered for inclusion despite them (supposedly) matching jQuery selectors.
Question
I have some code below that uses checkboxes but emulates radio button behavior. In other words, only one checkbox can (validly) be selected at any time. No more than one should be selected.
If you run the example below and click on the first 3 checkboxes, they will behave like radio buttons. Only one will be selected, no matter how many you click.
However, if you Add Point, newly added points will not be considered for the JS even though in theory it should grab them too...
Specifically: You can select the newly added checkbox, and it will be selected in addition to one already selected previously. That is incorrect as only 1 should be selected at any time and all others should be unselected.
What is happening and how can I have newly added nodes be included into jQuery selectors?
$(function() {
//check first box
$("input.duty:first").prop("checked", true);
//clicking unchecked box should check that box
//unchecks all others
$(".duty").on('click', function(event) {
$("input.duty").prop("checked", false);
$(this).prop("checked", true);
});
$("#addCasePoint").on("click", function() {
var newRowIndex = $('#newRowIndex').text();
var template = $('#casePointTemplate').data('template');
template = template.replace(/__index__/g, newRowIndex);
$('#casePointsFieldset').append(template);
$('#newRowIndex').text(++newRowIndex);
return false;
});
//deletes case point
$("#selection").on("click", ".removeCase", function() {
var caseCount = $('#selection .casePointFieldset').length
if (caseCount === 1) return false; //keep at least one row
$(this).closest("fieldset").remove();
return false;
});
});
.casePointFieldset {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="selection">
<fieldset id="casePointsFieldset">
<legend>Case Points</legend>
<div id="pointFieldset">
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
</div>
<!-- include template -->
<span id="casePointTemplate" data-template="<fieldset class="casePointFieldset"><div><label><span>Duty:</span> <input name="point[__index__]" class="duty" value="1" type="checkbox"></label></div><button class="removeCase">Remove</button></fieldset>">
</span>
</fieldset>
<button id="addCasePoint">Add Point</button>
</form>
The problem is how you're binding to them. The .click function (or .on('click')) basically works like this:
Find all of the currently existing elements which match a selector ($('.your.selector.here'))
Attach an event handler to each of those elements
Notice how I mentioned it binds to ones which already exist? That means it won't bind to newly created ones automatically. However, you can use .on to bind to the parent of those elements then listen for events on a selector. I'll show you what I mean:
$('#addItem').click(function() {
$('.container').append('<button class="item">Item</button>');
});
// Notice that I'm binding to the parent
// then specifying which events from it's children
// I want to listen to (click events from .item elements)
$('.container').on('click', '.item', function() {
console.log("I'm an item");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<button class="item">Item</button>
</div>
<button id="addItem">Add New Item</button>
If you change your on('click' to work like that then you'll have no problems.
Easiest way will be, attaching the event to the document. In the past this was done with the live() method.
$(document).on('click', '.duty', function(event) {
$("input.duty").prop("checked", false);
$(this).prop("checked", true);
});

DIV losing focus when clicking on elements inside it

Why does the DIV lose focus when i click on elements inside it?
I have an JS that hides the DIV when it loses focus. But that should not happen when clicking on elements inside the DIV.
It needs to be done with .on because there is some ajax loading going on.
$(document).on('focusout', '#geomodal', function(e) {
console.log('.focusout');
});
<div id="geomodal" tabindex="-1">
<input value="109" name="districts[]" type="checkbox">
<label>Bla</label>
<br>
<input value="152673" name="districts[]" type="checkbox">
<label>Blabla</label>
<br>
</div>
http://jsfiddle.net/2g41su81/2/
jQuery Documentation:
The focusout event is sent to an element when it, or any element
inside of it, loses focus.
Only one element has focus at a time - if an input has focus, your div doesn't. After losing focus, check if the newly-focused element is your div or a child, and don't hide it in that case.
$(document).on('focusout', '#geomodal', function (e) {
setTimeout(function(){
var focus=$(document.activeElement);
if (focus.is("#geomodal") || $('#geomodal').has(focus).length) {
console.log("still focused");
} else {
console.log(".focusout");
}
},0);
});
The setTimeout is necessary to allow the new element to gain focus before doing the check.
http://jsfiddle.net/2g41su81/5/
you can also use e.relatedTarget to get the element which caused the focusout to be triggered and do handling according to that!
check this example.
the focusout event is not execute while click on inner elements
Check the "tabindex" attribute, is the trick
Html Code
<div id="mydiv" tabindex="100">
<div class="anotherdiv">
<input type="checkbox" name="" value=1>
</div>
<div class="anotherdiv"> child content
<input type="checkbox" name="" value=1>
</div>
</div>
http://jsfiddle.net/tierrarara/kPbfL/425/
JS Code
$("#mydiv").focusin(function() {
$("#mydiv").css("background","red");
});
$("#mydiv").focusout(function() {
$("#mydiv").css("background","white");
});
CSS Code
#mydiv{
width : 50px;
height:auto;
border : 1px solid red;
}
.anotherdiv{
width : 50px;
height:50px;
border : 1px solid blue;
}

Moving button doesn't receive click event

I have a text field which should hide when it loses focus. I also have a button. The problem is, when you click the button, the text field first loses focus, which moves the button, preventing it from receiving the click event.
HTML:
<div>
<p> Focus on the text field, and then click the button </p>
<div id="hideMeOnFocusOut">
<input type="text" id="focusMeOut" autofocus>
<br><br><br>
</div>
<button id="clickMe">click me</button>
</div>
JS:
$(function() {
$('#focusMeOut').on('focusout', function(e) {
$('#hideMeOnFocusOut').hide();
});
$('#clickMe').on('click', function(e) {
alert('clicked!');
});
});
http://jsfiddle.net/u86ycf5e/
The button should still move. But it should also receive the click event.
Add a container with a height around the element you are hiding: Fiddle
.container {
height: 50px;
}
HTML
<div class="container">
<div id="hideMeOnFocusOut">
<input type="text" id="focusMeOut" autofocus>
<br>
<br>
<br>
</div>
</div>
Alternatively, you could make the element hide after a short delay via setTimeout like so:
$('#focusMeOut').on('focusout', function (e) {
setTimeout(function() {
$('#hideMeOnFocusOut').hide();
}, 250);
});
Other fiddle
Try ...
$('#focusMeOut').on('focusout', function(e) {
$('#hideMeOnFocusOut').hide();
if (e.relatedTarget.id==="clickMe") {
$("#clickMe").trigger('click');
}
});
This will check to see if the button was clicked and fire it ...
Hide the text box instead with:
$('#focusMeOut').on('focusout', function(e) {
$(this).hide(); //this line changed
});
and optionally set the height of the <div> to prevent button moving with this CSS:
#hideMeOnFocusOut {
height:80px;
}
You might want to rename your IDs more appropriately now.
http://jsfiddle.net/u86ycf5e/4/

adding div around link using jquery

I am adding a div around a link on click of a button. but when i click button multiple times, it adds multiple divs.
<li>
<label> </label>
<div class="deletebutton">
<label> </label>
<div class="deletebutton">
<label> </label>
<div class="deletebutton">
<input type="button" id="ctl00_ContentPlaceHolder1_ctrlAddPhotos_RadUpload1remove1" value="Remove" class="ruButton ruRemove" name="RemoveRow">
</div>
</div>
</li>
How can i make sure that it first checks if there is a div around link and then adds.
I am using following code:
var parentTag = $(".ruRemove").parent().get(0).tagName;
if (parentTag == 'LI') {
$(".ruRemove").wrap("<div class='data deletebutton'></div>");
$(".deletebutton").before("<label></label>");
} else {
var par = $('.deletebutton').parent();
if (par.is('div')) par.remove();
$(".ruRemove").wrap("<div class='data deletebutton'></div>");
var prev = $('.deletebutton').prev();
if (prev.is('label')) prev.remove();
$('.deletebutton').before("<label></label>");
}
it should become this:
<li>
<label> </label>
<div class="deletebutton">
<input type="button" id="ctl00_ContentPlaceHolder1_ctrlAddPhotos_RadUpload1remove1" value="Remove" class="ruButton ruRemove" name="RemoveRow">
</div>
</li>
when i click button. before clicking html is:
<li>
<input type="button" id="ctl00_ContentPlaceHolder1_ctrlAddPhotos_RadUpload1remove1" value="Remove" class="ruButton ruRemove" name="RemoveRow">
</li>
Here is a solution shown in a jsFiddle.
The code story is
HTML
<button id="myButton">My Button</button
JavaScript
$(function() {
$("#myButton").click(function() {
if ($(this).parent().get(0).tagName !== "DIV") {
$(this).wrap("<div class='myDiv'>");
}
});
});
What the code does is register a callback for a button click. When clicked, we ask for the parent of the button that was clicked and ask if the parent node has a tag name of "DIV" meaning it is a <div>. If it is not a div, then we wrap the button in a div and end. On the next call, the detection of the parent being a div will be true and no new div will be added.
Why don't you just use for example a function that does what you want only on the first click?
So only on the first click of that button adds the div, if you click other times the button, it wont do anything. This way you wont add multiple divs.
To do that you could use for example jQuery:
<script type="text/javascript">
$("#firstclick").one("click",function() {
alert("This will be displayed only once.");
});
</script>
You can check even the jQuery API Documentation regarding one:
http://api.jquery.com/one/

Categories

Resources