I'm generating and appending several spans to divs on page load.
HTML structure like:
<div id="holder">
<div id="grid"></div>
</div>
Then loop through and append spans to the nested div:
$span = $('<span />').attr('class', 'colorSquare');
$("#grid").append($span);
Then, I want to click a button and reset (delete the originally appended spans, because I don't want to reappend spans) what's inside the div's with:
$("#holder > div").html("");
On initial page load / initial generation of spans inside the div, the click event handler is registered to the div's spans on document.ready , and the following works:
$("#grid span").click(function () { console.log("working"); });
However, after resetting with $("#holder > div").html("");, the click handler doesn't work. I'm assuming this is because the handler is only assigned on initial document ready, but I wasn't expecting all handlers to be removed once you reset the div's content. How do I prevent assigned handlers from being removed?
This is because you are assigning the click handler onto the span element that you have added to #grid. When you clear #grid, you also remove the span and therefore you lose the click handler. You will either have to re-assign the handler again as soon as another span is created, or use an alternate handler that is tied to an element that does not get removed (such as #grid):
$('#grid').on('click', 'span', function() { console.log("working"); });
This alternative uses jQuery's on method, and binds the handler to the #grid element. However, the second parameter labels that you only care about clicking on span elements which are children of #grid.
Related
In this example, I've created a label group with a header, and have attempted to attach a click listener to each label; I eventually want an input inside each label, but it is not necessary to illustrate the behavior I don't understand.
I am seeing different behavior depending on whether I wrap the label text in a span tag:
When the label without a child span is clicked, the event handler is called once as I would expect, on the label element.
When the label with a child a span is clicked, the event handler is still called only once, but this time for the child span and not for the parent label.
I would have expected, in the second scenario, the event handler to trigger twice: once for the parent label, and once for the child span. Can someone explain why the addition of this span element seems to be preventing the event handler from propagating to the parent label?
var settingsGroup = document.getElementById("settings");
settingsGroup.querySelectorAll('.setting').forEach(function(setting) {
var options = setting.querySelectorAll('label');
options.forEach(function(option) {
option.addEventListener("click", function(ev) {
console.log(`${this.id} clicked: ${ev.target.tagName}`);
});
});
});
<div id="settings">
<div class="setting" role="group">
<div id="header">
<em>
A setting
</em>
</div>
<label id="option-a">
Option A
</label>
<label id="option-b">
<span>
Option B
</span>
</label>
</div>
</div>
This is normal. e.target is the element that was the target of the event (the span in the case of <label><span>...</span></label>. The target of the event is the span, and then the event propagates (bubbles) to its parent label, where it gets handled by your event handler.
If you want to look at the label instead, either use this as you have for id, or use e.currentTarget (the element the event is currently being delivered to).
This diagram from the old DOM3 Events spec is handy for understanding event flow:
You can use "pointer-events" CSS directive to stop span HTML elements receiving mouse events.
span
{
pointer-events: none;
}
I am new to HTML and JS.
Need to create dynamic expand-collapse list.
var parentId = document.getElementById("ABCD")
parentId.setAttribute("data-toggle","collapse")
parentId.setAttribute("data-target","#collapse1")
var tag = document.createElement("ul");
tag.setAttribute("id","collapse1")
tag.appendChild(document.createTextNode("PQR"))
parentId.appendChild(tag)
Trying for list as-
ABCD
PQR
So in this case, when i am clicking on ABCD, PQR gets expanded/collapsed.
But the problem is on clicking on PQR, it gets collapsed again.
So does the properties of parent gets applied to child node also?
it's not that it gets properties of it's parent, this has to do with how events handled, specifically event bubbling. When you click a child element, a click event if fired for all parent elements of what you clicked on
to cancel the event from bubbling when you click the appended elements you need to event.stopPropagation() inside of a click handler for the new elements
after you append them do the following
// tag.appendchild code goes here, then do the following
document.querySelector("#collapse1").onclick=function(event){
event.stopPropagation();
}
also, i should mention all this would be 10 times easier with jQuery
Is there any difference between a div cloned and a div generated in a loop ?
I have two situations:
div 1 :
$('.div1').clone(true).insertAfter('.created_form');
div 2 :
loop
<div class="div2"></div>
endloop
I have a button in each div, to delete the div when the button is pressed.
But the button for delete work only for the cloned div (div1).
For div 2 is not working.
My code for deleting the div is :
$('.buttons').on('click', '.minus_sign', function() {
var parent_id = $(this).parent().attr('id');
$("#"+parent_id).remove();
$("input[name='"+parent_id+"']").remove();
});
Can someone tell me why this is not working for both please ? I mention that the div is exaclty the same, only the id is different! Thank you
That's because the one created without the clone doesn't have an id attribute.
<div class="div2"></div>
However, if you were give it an id:
<div id="myDiv" class="div2"></div>
it would work.
Assuming the original element had an id attribute, the one you're creating inside the loop doesn't have an id attribute as mentioned in this answer.
Even if it has one, since you're using .clone(true), the clone will have the data and event handlers of the cloned element.
But the one created inside loop does not contain the event handler.
And the event delegation will not work since you're delegating the click of .minus_sign to the button which is also dynamically created.
You should delegate the event handler to a static element, for example
$(document).on('click', '.buttons .minus_sign', function() {
var parent_id = $(this).parent().attr('id');
$("#"+parent_id).remove();
$("input[name='"+parent_id+"']").remove();
});
BTW, Since remove() method returns the removed element, you can do the above like
$(document).on('click', '.buttons .minus_sign', function() {
var parent_id = $(this).parent().remove().attr('id');
$("input[name='"+parent_id+"']").remove();
});
I'm working on something that creates a form based on choices you give it (text/textfield/dropdown). When I create 2 dropdowns at once I am not sure how to write in a way that the computer can tell the 2 elements aren't the same, specifically when adding new inputs in my dropdown creator it can't tell multiple dropdowns apart.
Here's the Javascript function I'm using for it
$('#submit').on('click', function() {
$("select").each(function() {
switch($(this).val()) {
case "text":
$("#form").append('<p><input type="text"/> <button class="remInput">Remove</button></p>');
break;
case "note":
$("#form").append('<p><textarea></textarea> <button class="remInput">Remove</button></p> ');
break;
case "dd":
$("#form").append('<p><select id="ddFinal"><option></option></select> <button class="remInput">Remove</button></p>');
$("#ddCreator").append('<button id="ddAddInput">Add Another Field</button> <p class="ddP"><input type="text" name="ddText"/></p> <button id="ddSubmit">Submit</button>');
break;
}
});
$('#inputDiv').empty();
$('#ddAddInput').on('click', function() {
$("p[class*='ddP']").append('<input type="text" name="ddText"/>');
});
$('#ddSubmit').on('click', function() {
$("input[name*='ddText']").each(function() {
$('#ddFinal').append('<option>'+$(this).val()+'</option>');
});
$('#ddCreator').empty();
$('#ddFinal').removeAttr('id');
});
});
The problem is with the ddAddInput function because it doesn't specify between multiple p class="ddp" elements but I'm not really sure what I should be putting instead. Hope this question makes sense.
Here's the fiddle I'm currently working on http://jsfiddle.net/me74Z/15/
There are several flaws in approach that need to be remedied.
First: - element Id's are unique in a page by definition. Use classes instead.
Next, your event handlers are being added from within another event handler. If you were to change all the ID's you have to classes and the corresponding selectors in the event handlers, you would end up compounding events.
What compounding events means is if you add the same handler twice to an element, it will fire twice.
Using event delegation would be easier. Set up your event delegation outside of the current click handler for #submit
$(document).on('click', '.ddSubmit', function() {....});
Now, as for how to handle instances, within every event handler this is the element that is the target of the event.
Using $(this) and jQuery traverse methods you can work with the target's parent and siblings or whatever you need to do.
I would suggest you wrap each level in a container to simplify the traversals. I'll call container class row so that a generic traverse from an event target can look something like:
var someField= $(this).closest('.row').find('.someField');
WHen remove button is clicked, simply remove the parent row
I have two DIV tags.
1) Green Color is outer Div Tag which has onclick property set to alert('Clicked').
2) Yellow Color is Inner DIV Tag
Now, when I perform a click on inner div tag an alert pops up. Same repeats while selecting items from inner div tag. I'm not able to select in the inner div tags. How can this be resolved?
Further more, I will have nested div tags which are generated dynamically. I'm stuck here
You need to prevent the propagation of your click up to the outer div.
Sorry about the repost, but the answer is already located at:
event.preventDefault() vs. return false
One solution is to set an event listener on your outer container, and, when the listener is triggered, only act after you have verified that the click did not originate from any of the container's children (in this case, inner). You could tweak this solution to only exclude specific children by class, id, etc:
$(document).ready(function() {
var outer = $('.outer');
outer.on('click', handleOuterClick);
function handleOuterClick(e) {
//Assert that the click originated from the outer div, and not from
//any of its children
var origin = e.target,
children = outer.children();
if(children.index($(origin)) == -1) {
//Proceed by displaying an alert
alert("You clicked the outer div!");
}
};
});
Here's the fiddle: http://jsfiddle.net/39ssk/
Check this out. You can apply id, and use those ids to control onclick.
<html><head></head>
<body>
<script type="text/javascript">
function manualToggle(val)
{
alert(val.id);
}
</script>
<div id="test" onclick="manualToggle(this);">
<span>Allowed to click</span>
<span onclick="event.cancelBubble=true;if (event.stopPropagation) event.stopPropagation();">Not allowed to click</span>
<span>Allowed to click</span>
</div>
</body>
</html>