Javascript click event triggers twice - javascript

In the following snippet, why does divClicked() trigger twice when the <label> is clicked, but only once when <input> is clicked?
function divClicked(_index) {
console.log("div click event");
}
function inputClicked(_index) {
console.log("input click event");
}
<div class="option" onclick="divClicked(1)">
<input id="1_1" name="group_1" type="radio" value="1" onclick="inputClicked(1)" />
<label for="1_1">label</label>
</div>
Note: I want to know why this happens, not a "quick fix" like: put onclick() on label.

This happens because of what the HTML spec describes at 4.10.4:
For example, on platforms where clicking a checkbox label checks the
checkbox, clicking the label in the following snippet could trigger
the user agent to run synthetic click activation steps on the input
element, as if the element itself had been triggered by the user:
<label><input type=checkbox name=lost> Lost</label>
On other platforms, the behavior might be just to focus the control,
or do nothing.
This means that when a <label> is clicked, the browser creates a second "synthetic" click event on the associated <input> element, in order to toggle its state.
The reason divClicked is triggered twice, is because the first event which comes from the <label> bubbles up to the <div>, and also the second, synthetic click event bubbles up to the <div>.

This is usually be cause of the bubbling principle of click event:
When an event happens on an element, it runs on it, its associated elements,its parent and other ancestors.
Now, The relation is when you click on label there a are two events which bubbles up here:
1) Click on div (which you expect)
2) Click on input (which is also expected)
2.1) When click on input is triggered then a click on div is also triggered again here
You can confirm this behavior by using event.bubbles prop.
EDIT:
The reason for the connection between label and input: (I know this is absolutely not required, as it's present all over the place yet)
A <label> can be associated with a control either by placing the control element inside the <label> element, or by using the for attribute. Such a control is called the labeled control of the label element. One input can be associated with multiple labels.
Taken from: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label
Which means placing for on label referencing id of an input element will stimulate the behavior as if the element is inside the label. This would bubble a event on input onto label like any event on child to parent

At some moments, check also if the javascript file asset isn't loaded twice .... it shouldn't happen, but you never know.

Related

onBlur attached to div getting called while moving from one input element to other present in the same div

So I have a div and inside that div I have two input fields, like:
<div>
<input placeholder="Input1"/>
<input placeholder="Input2"/>
</div>
I wanted to call certain function whenever user clicks away from that div (not input fields).
So I attached onBlur event for that particular div, by giving it a tabIndex.
<div tabIndex="1" onClick={handleClick} onBlur={handleOnBlur}>
But now the onBlur event is getting triggered whenever I move from one input field to another input field residing in the same div.
I couldn't understand why this is happening. Also is there any better approach to achieve this sort of functionality.
Codesandbox link to play-around:
https://codesandbox.io/s/tender-carson-9rkj13
By passing in the event as a parameter to your handleOnBlur function, you can make use of currentTarget and relatedTarget properties, and discard events where the relatedTarget (<input>) is a child of the currentTarget (<div>).
For example:
const handleOnBlur = (event) => {
if (event.currentTarget.contains(event.relatedTarget)) {
return;
}
console.log("On blur for div called, setting false");
setShowBtn(false);
};

Click event handler on a div with label get triggered twice [duplicate]

In the following snippet, why does divClicked() trigger twice when the <label> is clicked, but only once when <input> is clicked?
function divClicked(_index) {
console.log("div click event");
}
function inputClicked(_index) {
console.log("input click event");
}
<div class="option" onclick="divClicked(1)">
<input id="1_1" name="group_1" type="radio" value="1" onclick="inputClicked(1)" />
<label for="1_1">label</label>
</div>
Note: I want to know why this happens, not a "quick fix" like: put onclick() on label.
This happens because of what the HTML spec describes at 4.10.4:
For example, on platforms where clicking a checkbox label checks the
checkbox, clicking the label in the following snippet could trigger
the user agent to run synthetic click activation steps on the input
element, as if the element itself had been triggered by the user:
<label><input type=checkbox name=lost> Lost</label>
On other platforms, the behavior might be just to focus the control,
or do nothing.
This means that when a <label> is clicked, the browser creates a second "synthetic" click event on the associated <input> element, in order to toggle its state.
The reason divClicked is triggered twice, is because the first event which comes from the <label> bubbles up to the <div>, and also the second, synthetic click event bubbles up to the <div>.
This is usually be cause of the bubbling principle of click event:
When an event happens on an element, it runs on it, its associated elements,its parent and other ancestors.
Now, The relation is when you click on label there a are two events which bubbles up here:
1) Click on div (which you expect)
2) Click on input (which is also expected)
2.1) When click on input is triggered then a click on div is also triggered again here
You can confirm this behavior by using event.bubbles prop.
EDIT:
The reason for the connection between label and input: (I know this is absolutely not required, as it's present all over the place yet)
A <label> can be associated with a control either by placing the control element inside the <label> element, or by using the for attribute. Such a control is called the labeled control of the label element. One input can be associated with multiple labels.
Taken from: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label
Which means placing for on label referencing id of an input element will stimulate the behavior as if the element is inside the label. This would bubble a event on input onto label like any event on child to parent
At some moments, check also if the javascript file asset isn't loaded twice .... it shouldn't happen, but you never know.

Event Control with KeyPress 'Tab'

So I have several input forms that are disabled until they are filled out in sequence because of data calls to the server based on their selections. I have a custom dropdown that allows me to do a typeahead and click the item I want. When I click the item, the field unlocks with a combination of onblur and onchange events that take place for my data model. The issue that comes into play for me is I want the user to be able to tab. But when I hit tab, the onblur and onchange haven't disabled the field so it skips several fields that it shouldn't. Is there any suggestions on preventing a tab keypress skipping the disabled element? Can I tab and focus on a disabled element?
That is not possible, as the docs say:
A form control is disabled if its disabled attribute is set, or if it is a descendant of a fieldset element whose disabled attribute is set and is not a descendant of that fieldset element's first legend element child, if any.
A form control that is disabled must prevent any click events that are queued on the user interaction task source from being dispatched on the element.
So you can not click on those elements, and you can not focus element, that can not be clicked.
https://www.w3.org/TR/html5/forms.html#concept-fe-disabled
So the only option if you need to allow focusing of those elements is not to use disabled attribute at all. You could use .disabled class instead and bind on key events to suppress editing of the value.
Assuming you are willing to temporarily enable the disabled element (thus making it writable), this can be done by checking whether the next element has the disabled attribute with hasAttribute(). If it does, you can change this attribute to false before the keydown returns true, and thus the keyup will tab to the disabled element.
Additionally, you can set a new attribute wasDisabled, which you can then check against with $(this)[0]. If the element has this class, you can re-disable the element once you tab off it again.
This can be seen in the following jQuery example:
$('input').on('keydown', function(e) {
if (e.keyCode == 9) {
if ($(this).next()[0].hasAttribute('disabled')) {
$(this).next().attr('disabled', false);
$(this).next().attr('wasdisabled', true);
}
if ($(this)[0].hasAttribute('wasdisabled')) {
$(this).attr('disabled', true);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input>
<input disabled>
<input>
Hope this helps! :)
I ended up switching it to a readonly property. The readonly allowed me to tab to it and focus on it while not being able to type in it until the the blur and change completed.

Calling a click event handler on run-time HTML element

I have an HTML file, in which I am creating a text area when user clicks inside a table cell. Basically, it is a datagrid created using table, and when user clicks on one, it removes the text in cell and replace it with a text area. Below is the code I am using in table's onClick handler.
summaryTableElement.innerHTML = "<textarea id='summaryTextBox' value='TestString' onclick='doNothing(this.id)'> </textarea> <input type='button' onclick='saveSummary()' value='Save' /> "
This is all working fine, and it creates a text area perfectly. It bugs out when user clicks on the text area to modify the data. In that case, the click event handler of the text area never fires. Instead, the table receives the click event, resulting in creating another text area. No matter what user does, the text area receives no event at all.
Now, I am confused as to what to do here.
Edit:
I checked again. turns out, it is firing the child's click event handler. But, event is propagating to parent element too.
Edit:
I tried adding following condition in parent's click event handler
if (id.toString() == "SummaryData")
but this returns true even for child element.
Use a flag indicating the click once. If it is clicked already, then don't run the function. Now the problem of the text area. in your dynamically getting created html code, add an onfocus event handler insteaad of onclick. Also the 'id's cannot be the same for all the text areas you are adding dynamically. Use something like "id='xyz"+i+"'" where 'i' represents a count which is the number of the text area getting added.

Bind JavaScript jQuery click event on label AND on checkbox simultaneously

I'm using labels for my form, like this :
<label for="foo" id="bar">Label</label>
<input type="checkbox" id="foo" />
I want to hide an element when the user uncheck the box, and show it otherwise.
The problem is, if I bind the click event to "foo", it'll only works when the user clicks on the checkbox itself and not on the label. Therefore, do I also need to bind a click event on the label ? Or should I enclose both elements within a span ?
My HTML already contains 2344 elements, so I'd like to do it without adding anything, and without doubling the JavaScript code or the selector, if possible.
Instead of binding with the click() event, you should bind using the change() event, then however this change is triggered the outcome will be the same:
$('#foo').change(
function(){
// do whatever
});
References:
change().
The change event should fire for the input whether the label or input is clicked:
$("#foo").change(function () { ... });
Example http://jsfiddle.net/andrewwhitaker/6LMXW/

Categories