How to remove/disable submit on appendTo Elements? - javascript

I've created a function to focus the next input with the enter key and disabled the submit on the form. It works fine but when I add an input field with the appendTo function it will reactivate the submit function on my form. I want to focus the input fields with the enter key and not with tab key.
Here is my function:
$('input').keydown(function (e) {
if (e.which === 13) {
var index = $('input').index(this) + 1;
$('input').eq(index).focus().val("");
return false;
}
});
And my appendTo function
var inputs = $('<input type="text" name="inputBasic[]" value="" class="form-control" />');
inputs.appendTo($("#dc_step_inputs"));
How can I remove the submit function when I add dynamical input field?
Thanks you for an answer!

You are binding your keydown event handler to a static set of elements (which does not include any elements added dynamically after your event handler has been attached), use delegation to bind to any elements that show up under your form:
$('#parent-form-id').on('keydown', 'input', function(e){
if (e.which === 13) {
var index = $('input').index(this) + 1;
$('input').eq(index).focus().val("");
return false;
}
});

$('input') only affects the elements that exist at the time this function runs.
You need to run the same script on the inserted element(s) too:
var inputs = $('<input type="text" name="inputBasic[]" value="" class="form-control" />');
inputs.appendTo($("#dc_step_inputs"));
inputs.keydown(function (e) {
if (e.which === 13) {
var index = $('input').index(this) + 1;
$('input').eq(index).focus().val("");
return false;
}
});

you can name your key down function
$('input').keydown(keydown);
function keydown(){
if (e.which === 13) {
var index = $('input').index(this) + 1;
$('input').eq(index).focus().val("");
return false;
}
and when you create a new input, give it an id, like this:
var inputs = $('<input id="newInput" type="text" name="inputBasic[]" value="" class="form-control" />');
inputs.appendTo($("#dc_step_inputs"));
and then
$('#newInput').keyDown(keyDown);

As has already been mentioned, when you add an event listener to a DOM element in JavaScript, you set it again the element itself, rather than a selector, or a given collection of elements.
One way around this, is to add an event listener to a common parent of all the elements for which you wish your event to be triggered against. This process is called Event Delegation. Fortunately, in jQuery this is very simple, using the following syntax:
$(<parent_selector>).on(<event>, <child_selector>, <fn>);
From the example you provided this might look something like (presuming you only want to target inputs within #dc_step_inputs):
$("#dc_step_inputs").on("keydown", ":input", function(e) {
if (e.which === 13) {
var index = $('input').index(this) + 1;
$('input').eq(index).focus().val("");
e.preventDefault(); // Note, this is preferred to return False
}
});

Related

triggering the function onchange of value in hidden input field [duplicate]

Can I attach any event handlers to HTML hidden input fields? Basically I want to run a function when a hidden input field value changes.
Events are only triggered when the user performs the event in the browser, so if it's <input type="hidden"> or an <input> hidden by CSS, the user won't be able to trigger events to your input.
The only way you would get onchange to work is if you manually trigger onchange in Javascript. A quick example of this:
<form name="f" onsubmit="document.f.h.value='1';
document.f.h.onchange();
return false;"
>
<input type="hidden" name="h" value="0" onchange="alert(document.f.h.value);" />
<input type="submit" />
</form>
Yes, certain browsers (such as Firefox) will fire an onclick or onfocus event on hidden elements when they're activated via an accesskey attribute (meant to provide a keyboard hotkey to jump to an input).
Open the below in firefox, focus the frame, then strike Alt+Shift+x (Windows and Linux) or Ctrl+Alt+x (Mac).
<input type="hidden" accesskey="x" onclick="alert('clicked!');" />
JavaScript has focus events for the elements. There are three focus events: focus, focusin, and focusout.
I discovered focusout will trigger when an element display state is change for both block and none, while focusin only triggered for display state of block.
document.getElementById('element_id').addEventListener('focusout',function(e){
if (this.style.display === "none") {
// perform operations when the element is hidden, like clear fields, etc.
} else {
// perform operations when the element is displayed, like populate fields
}
});
Facing the problem I needed to react on change of hidden inputs which were modified by code which was out of my control, I got inspired by JS onchange hack for input[type=hidden] and created following solution for my problem using MutationObserver
Request:
I want to have function FAM.processFields run whenever any of selected subset of form fields (expressionFields) changes its value.
Problem:
Some of the form fields are of type="hidden", so change event is never fired for them.
Solution:
var index, elementId, element;
var elementIdPrefix = g_form.getTableName() + ".";
var expressionFields = this.getExpressionFieldNames();
// As trigger either Event or MutationRecord is passed, depends on input type
var processFieldsCallback = (function(trigger) {
// Relies on instance of - FAM object - added in onLoad script
FAM.processFields();
});
var changeOfValueConfig = {attributeFilter: ["value"]};
var processFieldsObserver = new MutationObserver(processFieldsCallback);
if (this.debug) {
console.log("addChangeEventListeners to expressionFields");
console.log(expressionFields);
}
for (index = 0; index < expressionFields.length; index++) {
elementId = elementIdPrefix + expressionFields[index];
element = document.getElementById(elementId);
// In case of hidden input (e.g. glideList, fieldList, checkbox) we need to register an observer to it
if (element.getAttribute("type") && element.getAttribute("type").toLowerCase() == "hidden") {
processFieldsObserver.observe(element, changeOfValueConfig);
if (this.debug) {
console.log("register processFieldsObserver of changeOfValueConfig on elementId " + elementId);
console.log(element);
}
}
else {
element.addEventListener("change", processFields);
if (this.debug) {
console.log("addChangeEventListeners on elementId " + elementId);
console.log(element);
}
}
}
Facing the problem I needed to react on change of hidden inputs which were modified by code which was out of my control, I got inspired by JS onchange hack for input[type=hidden] and created following solution for my problem using MutationObserver
Request:
I want to have function FAM.processFields run whenever any of selected subset of form fields (expressionFields) changes its value.
Problem:
Some of the form fields are of type="hidden", so change event is never fired for them.
Solution:
var index, elementId, element;
var elementIdPrefix = g_form.getTableName() + ".";
var expressionFields = this.getExpressionFieldNames();
// As trigger either Event or MutationRecord is passed, depends on input type
var processFieldsCallback = (function(trigger) {
// Relies on instance of - FAM object - added in onLoad script
FAM.processFields();
});
var changeOfValueConfig = {attributeFilter: ["value"]};
var processFieldsObserver = new MutationObserver(processFieldsCallback);
if (this.debug) {
console.log("addChangeEventListeners to expressionFields");
console.log(expressionFields);
}
for (index = 0; index < expressionFields.length; index++) {
elementId = elementIdPrefix + expressionFields[index];
element = document.getElementById(elementId);
// In case of hidden input (e.g. glideList, fieldList, checkbox) we need to register an observer to it
if (element.getAttribute("type") && element.getAttribute("type").toLowerCase() == "hidden") {
processFieldsObserver.observe(element, changeOfValueConfig);
if (this.debug) {
console.log("register processFieldsObserver of changeOfValueConfig on elementId " + elementId);
console.log(element);
}
}
else {
element.addEventListener("change", processFields);
if (this.debug) {
console.log("addChangeEventListeners on elementId " + elementId);
console.log(element);
}
}
}
You can still trigger events on hidden input using labels
The accepted answer claims that: "The user won't be able to trigger events to your input.", but this is not true.
A label connected to an input element can also trigger an input, so even though the input element itself is hidden, if properly connected to a label the user can trigger the input by its label:
There are two ways to connect an input to a label,
Use the id of the input element in the for attribute:
<label for="checkbox">Label</label><input type="checkbox" id="checkbox"/>
Or simply wrap the input inside a label:
<label><input type="checkbox"/>Label</label>
See a working code example here in fiddle or below:
const onChange = (event) => {
console.log(event);
const checkbox = event.target;
alert("checkbox value is: " + checkbox.checked);
}
document.getElementById('checkbox').addEventListener('change', onChange);
input[type="checkbox"] {
visibility: hidden;
}
label {
font-weight: bold;
}
<label>
<input id="checkbox" type="checkbox"/>
label for hidden checkbox
</label>

How to move focus on next field when enter is pressed?

Can you please tell me how to move focus on to the next field when the enter key is press? I use the dform plugin (which converts JSON to a form).
I Googled it, but this not working. Why doesn't my focus move on to the next field?
JSFiddle: http://jsfiddle.net/5WkVW/1/
$(document).keypress(function(e) {
if(e.which == 13) {
// Do something here if the popup is open
alert("dd")
var index = $('.ui-dform-text').index(this) + 1;
$('.ui-dform-text').eq(index).focus();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form id="testSuiteConfigurationform" name="testSuiteConfigurationform" method="post" class="ui-dform-form" novalidate="novalidate">
<label class="ui-dform-label">
<h3>Configuration Parameters</h3>
</label>
<div class="ui-dform-div inputDiv">
<fieldset class="ui-dform-fieldset">
<input type="text" id="totalRetryCount" name="totalRetryCount" tabindex="1" onblur="validateElement('Configuration', 'testSuiteConfigurationform','totalRetryCount')" class="ui-dform-text valid">
<legend class="ui-dform-legend">Total Retry Count</legend>
<label for="totalRetryCount" class="checked">✔</label>
</fieldset>
<fieldset class="ui-dform-fieldset">
<input type="text" id="totalRepeatCount" name="totalRepeatCount" tabindex="2" onblur="validateElement('Configuration', 'testSuiteConfigurationform','totalRepeatCount')" class="ui-dform-text">
<legend class="ui-dform-legend">Total Repeat Count</legend>
</fieldset>
<fieldset class="ui-dform-fieldset">
<select id="summaryReportRequired" name="summaryReportRequired" tabindex="3" onblur="validateElement('Configuration', 'testSuiteConfigurationform','summaryReportRequired')" class="ui-dform-select">
<option class="ui-dform-option" value="true">true</option>
<option class="ui-dform-option" value="false">false</option>
</select>
<legend class="ui-dform-legend">Summary Report Required</legend>
</fieldset>
<fieldset class="ui-dform-fieldset">
<select id="postConditionExecution" name="postConditionExecution" tabindex="4" onblur="validateElement('Configuration', 'testSuiteConfigurationform','postConditionExecution')" class="ui-dform-select">
<option class="ui-dform-option" value="ALWAYS">ALWAYS</option>
<option class="ui-dform-option" value="ON_SUCCESS">ON_SUCCESS</option>
</select>
<legend class="ui-dform-legend">Post Condition Execution</legend>
</fieldset>
</div>
</form>
*Note (from comments): It also needs to work on pages that do not have tabindex values set
It fails because this is the document in your code.
You want to use the index of the currently focused item (document.activeElement), or if you use delegated events you can make sure this is the current item.
This final version works whether there are tabindexes or not. It also wraps around:
JSFiddle 1: http://jsfiddle.net/TrueBlueAussie/5WkVW/11/
JSFiddle 2: http://jsfiddle.net/TrueBlueAussie/5WkVW/12/
They both use a custom jQuery selector that I add called :focusable to select all focusable element (including links):
// register jQuery extension
jQuery.extend(jQuery.expr[':'], {
focusable: function (el, index, selector) {
return $(el).is('a, button, :input, [tabindex]');
}
});
$(document).on('keypress', 'input,select', function (e) {
if (e.which == 13) {
e.preventDefault();
// Get all focusable elements on the page
var $canfocus = $(':focusable');
var index = $canfocus.index(this) + 1;
if (index >= $canfocus.length) index = 0;
$canfocus.eq(index).focus();
}
});
You can use the same custom selector in the event handler if you like. Then it will even work on anchor links (if you change the event to keydown instead of keypress):
e.g.
$(document).on('keydown', ':focusable', function (e) {
Example with link: http://jsfiddle.net/5WkVW/15/
This also uses a delegated on, listening for the keydown event on the document. It then applies the jQuery selector, it then applies the function to any matching element that caused the event. This is much more efficient as it only applies the selector at event time (rather than apply multiple event handler to each DOM matching element).
Old versions below:
JSFiddle: http://jsfiddle.net/TrueBlueAussie/5WkVW/3/
$(document).keypress(function(e) {
if(e.which == 13) {
// Do something here if the popup is open
//alert("dd")
var index = $('.ui-dform-text').index(document.activeElement) + 1;
$('.ui-dform-text').eq(index).focus();
}
});
*Note: alerts can interfere with focus, so use console.log for output like that and view in most browser's debug window (like Chrome's F12 debugging tools).
Update: http://jsfiddle.net/TrueBlueAussie/5WkVW/4/
This one wraps back to the first item from the last and also works on selects (the default behavior is blocked, so you can only use space to open or up/down to select options.
$('input,select').on('keypress', function (e) {
if (e.which == 13) {
e.preventDefault();
var $next = $('[tabIndex=' + (+this.tabIndex + 1) + ']');
console.log($next.length);
if (!$next.length) {
$next = $('[tabIndex=1]');
}
$next.focus();
}
});
Requested "document" version: http://jsfiddle.net/TrueBlueAussie/5WkVW/5/
$(document).on('keypress', 'input,select', function (e) {
if (e.which == 13) {
e.preventDefault();
var $next = $('[tabIndex=' + (+this.tabIndex + 1) + ']');
console.log($next.length);
if (!$next.length) {
$next = $('[tabIndex=1]');
}
$next.focus();
}
});
I've created a non-jQuery version. So only pure Javascript;
https://jsfiddle.net/mm0uctuv/2/
Javascript:
var inputs = document.querySelectorAll("input,select");
for (var i = 0 ; i < inputs.length; i++) {
inputs[i].addEventListener("keypress", function(e){
if (e.which == 13) {
e.preventDefault();
var nextInput = document.querySelectorAll('[tabIndex="' + (this.tabIndex + 1) + '"]');
if (nextInput.length === 0) {
nextInput = document.querySelectorAll('[tabIndex="1"]');
}
nextInput[0].focus();
}
})
}
HTML:
<form>
Field 1: <input type="text" tabindex="1"><br>
Field 3: <input type="text" tabindex="3"><br>
Field 2: <input type="text" tabindex="2">
</form>
On the top-level div, add onKeyDown={this.onKeyDown.bind(this)} and add the following method (ES6) to the same class as the div:
onKeyDown(event) {
if (event.keyCode === 13) {
event.preventDefault()
const inputs =
Array.prototype.slice.call(document.querySelectorAll("input"))
const index =
(inputs.indexOf(document.activeElement) + 1) % inputs.length
const input = inputs[index]
input.focus()
input.select()
}
}
The following code should do it; it uses the tabIndex property. Let us know if that's is not acceptable:
$(function() {
$('input').on('keypress', function(e) {
e.which !== 13 || $('[tabIndex=' + (+this.tabIndex + 1) + ']')[0].focus();
});
});
The drop down already has enter key slated for opening the drop down.
JS FIDDLE DEMO
To be able to do something before moving to the next form element, you can use the following version:
$(function() {
$(document).on('keypress', function(e) {
var that = document.activeElement;
if( e.which == 13 ) {
e.preventDefault();
alert( "dd" );
$('[tabIndex=' + (+that.tabIndex + 1) + ']')[0].focus();
}
});
});
DEMO
Try the following JavaScript code that I modified from your fiddle. The default behavior of the select elements will be to expand on the keypress. The plus sign at the beginning of +$(this).attr("tabindex")
Converts the text attribute value to int.
$(".ui-dform-text").keypress(function(e) {
if(e.which == 13) {
// Do something here if the popup is open
alert($(this).attr("tabindex"));
var index = +$(this).attr("tabindex") + 1;
$("[tabindex='" + index +"']").focus();
}
});
This is mostly a joke but here is a Vanilla JS version using the newest APIs as long as you have a modern browser, it should be bullet proof
Here's what's happening:
Select Elements, inputs, etc... (excluding disabled, hidden, etc...)
Using the spread syntax, convert array (NodeList) to an object (here it's NodeObject)
Loop through the Objects aka Elements aka Nodes
Each iteration will pass the current element (Node) and the next element (NextNode) to an arrow function.
Continue if NextNode is an element
Then add a keypress event to the current element
Inside the event:
Continue only if the enter key was pressed (using e.key NOT e.keyCode or e.which -- which are deprecated)
Stop the Form from being submitted
Focus the next element
If we can, Select the text in the next node
And just like that you have some really unreadable code that is mostly parenthesis and arrow functions :)
// NodeList of applicable inputs, select, button
let NodesArray = document.querySelectorAll(`
#form input:not([disabled])[type]:not([type=\"hidden\"]),
#form select:not([disabled]),
#form button:not([disabled])[type=\"submit\"]
`);
// Spread the array to an object so we can load the next node without
// keeping track of indexes (barf)
(NodesObject => {
// Node and NextNode are Elements.
// You can update and get data if you want
Object.keys(NodesObject).forEach(i => (({ Node, NextNode }) => {
// Break if we dont have a NextNode
if (NextNode === false) return;
Node.addEventListener('keypress', KeyboardEvent => {
// Only continue if event.key was "Enter"
if (KeyboardEvent.key !== "Enter") return;
// Dont submit, thx
KeyboardEvent.preventDefault();
// Do the thing
NextNode.focus();
// Not all elements have a select method
if (typeof NextNode.select === 'function') NextNode.select();
});
})({
Node: NodesObject[i],
NextNode: NodesObject[(parseInt(i) + 1)] ?? false
}));
})({ ...NodesArray });
it looks the same, but I offer something simple, maybe helpful, and easy to remember, and this is what I use
html
<input placeholder="nama">
<input placeholder="email">
<input placeholder="password">
<button>MASUK<button>
js
$('INPUT').keydown( e => e.which === 13?$(e.target).next().focus():"");
// This will work; add this code in your on ready function and define your parent element which includes child elements to be focused.
const mainDiv = document.getElementById(`auto-focuser`); //here your parent element you need to focus
const keyDownEvent = (event) => {
if (event.key === "Enter") {
if (event.target.tagName === "TEXTAREA" && (event.target.innerHTML !== "" && event.target.innerHTML.substr(-1) !== "\n"))
return;
if (event.target.attributes.tabindex) {
const nextElm = mainDiv.querySelectorAll(`[tabindex='${parseInt(event.target.attributes.tabindex.value) + 1}']`).item(0)
if (nextElm) {
nextElm.focus()
if (nextElm.tagName === "INPUT" || nextElm.tagName === "TEXTAREA") {
nextElm.select()
nextElm.selectionStart = nextElm.selectionEnd = nextElm.value.length;
}
event.preventDefault()
}
}
}
}
mainDiv?.addEventListener('keydown', keyDownEvent);
1.first = you should put 'textbox' on your class name in input
2.second = put specific id for each input
then write this code for select that element and go to next element.
I select each element by each id and put next() function on keypress of every input.
function next(event,elem){
if ( event.keyCode == 13)
{
var list = document.getElementsByClassName("textbox");
for (var i=0 ; i<list.length ; i++)
{
if (elem.id == list[i].id)
{
var index = i + 1;
list[index].focus();
}
}
}
}
event args use for keybord press//
elem args use for element that we press eneter

How to stay DRY - multiple inputs that trigger the same function on keypress?

This is the code that is working (but repetitive). I tried to replace the "getElementById" part with "getElementsByClassName", adding a class to the elements - but that didn't do it for me. Right now I have this anonymous function repeated once for each ID:
document.getElementById("gasCost").onkeypress = function(e) {
if(e.keyCode == 13) {
goButton();
}
}
HTML:
<input placeholder="How far are you going? (miles)" id="distance">
<input placeholder="How many MPG does your car get?" id="mileage">
<input placeholder="What's the average cost of gas?" id="gasCost">
Is it possible to define the function prior & call it to each ID? Is it possible to do it differently with classes? I'm open to all suggestions, but I'd prefer not to be using jQuery.
If you wanted to use classes you could do something like this:
function keyHandler(e) {
if(e.keyCode == 13) {
goButton();
}
}
var elements = document.getElementsByClassName("yourclasshere");
for (var i = 0; i < elements.length; i++)
elements[i].onkeypress = keyHandler;
(getElementsByClassName() returns a list, so you have to loop over each element in the list and bind a handler to them individually.)
Alternatively you could bind a single handler to a parent element that contains all of your inputs (perhaps to a form element?):
document.getElementById("someContainer").onkeypress = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (e.keyCode === 13 && e.target.tagName === "INPUT") {
goButton();
}
};
Demo: http://jsfiddle.net/9U9nn/
This works because the key events "bubble up" from the source element (your input) through all containers until they reach the document. (So, worst case, you could bind the handler directly to the document.) You can tell which element the event originated with by checking the event.target (or event.srcElement for older IE).
function submitOnEnter(e) {
if(e.keyCode == 13) {
goButton();
}
}
document.getElementById("gasCost").onkeypress = submitOnEnter;
document.getElementById("mileage").onkeypress = submitOnEnter;
Note that this is already the default behavior in HTML forms: pressing enter submits the form.

Multiple event listener in Javascript

How to add multiple event listeners in the same initialization?
For example:
<input type="text" id="text">
<button id="button_click">Search</button>
JavaScript:
var myElement = document.getElementById('button_click');
myElement.addEventListener('click', myFunc());
This is working correctly however I would like to have another event listener for this input filed in the same call if that is possible, so when user clicks enter or presses the button it triggers the same event listener.
Just one note. User needs to be focused on the input field to trigger an "enter" event.
Just bind your function to 2 listeners, each one of the wished element:
document.getElementById('button_click').addEventListener('click', myFunc);
document.getElementById('text').addEventListener('keyup', keyupFunc);
where the new function test if the user pressed enter and then execute the other function :
function keyupFunc(evt) {
if(evt.keyCode === 13) // keycode for return
myFunc();
}
Working jsFiddle : http://jsfiddle.net/cG7HW/
Try this:
function addMultipleEvents(elements, events){
var tokens = events.split(" ");
if(tokens.length == elements.length){
for(var i = 0; i< tokens.length; i++){
elements[i].addEventListener(tokens[i], (e.which == 13 || e.which == 48)?myFunc:); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([textObj,btnObj], 'click keyup');
UPDATE:
function addMultipleEvents(elements, events) {
var tokens = events.split(" ");
if (tokens.length == elements.length) {
for (var i = 0; i < tokens.length; i++) {
elements[i].addEventListener(tokens[i], myFunc); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([btnObj, textObj], 'click keyup');
function myFunc(e) {
if (e.which == 13 || e.which == 1) {
alert("hello");
}
}
Working Fiddle
I think the best way to do this is by using for loops.
const events = ["click", "mouseover"]
for (i in events) {
document.getElementById("button_click").addEventListener(events[i], () => myFunc())
}
The code above loops through every events inside an array and adds it to the button.
Yeah this is a good question and can apply to other scenarios. You have a form and a user will have input text field, a radio box, a select option. So now you want the submit button to go from disabled to enabled. You decide to add an event listener to check if fieldA and fieldB and fieldC is first to enable submit button.
If you use event listener on Keyup", and all your fields are valid, the submit button will become enabled only if the last field is a text field because the event will only be triggered when you let go the key. This means it will not trigger if the radio box or select option is selected with your mouse. We must not rely in the order the fields are filled for the logic to work. Again, If you use "click", it sucks, because user will have to click somewhere on page in order for the event listener to fire and run the logic. So i think we'll need an event lister on mouseup, keyup and change for this example below. I assume you made all your validations and variables for the form fields already. We need a function with parameters of multiple events names as a string, the element we want to target (document, or button or form), and a custom function that contains our logic.
// Create function that takes parameters of multiple event listeners, an element to target, and a function to execute logic
function enableTheSubmitButton(element, eventNamesString, customFunction) {
eventNamesString.split(' ').forEach(e => element.addEventListener(e, listener, false));
}
// Call the above function and loop through the three event names inside the string, then invoke each event name to your customFunction, you can add more events or change the event names maybe mousedown, keyup etc.
enableSubmitButton(document, 'keyup mouseup change', function(){
// The logic inside your customFunction
if (isNameValid && isLocationValid && isProjectValid){
publishButton.disabled = false;
} else {
publishButton.disabled = true;
// Do more stuff like: "Hey your fields are not valid."
}
});
// The isNameValid isLocationValid, isProjectValid are coming from your previous validation Javascript for perhaps a select field, radio buttons, and text fields. I am adding it as an example, they have to be equal to true.
// The publishButton is a variable to target the form submit button of which you want enabled or disabled based one weather the form fields are valid or not.
// For example: const publishButton = document.getElementById("publish");

Does HTML Hidden control have any events? Like onchange or something?

Can I attach any event handlers to HTML hidden input fields? Basically I want to run a function when a hidden input field value changes.
Events are only triggered when the user performs the event in the browser, so if it's <input type="hidden"> or an <input> hidden by CSS, the user won't be able to trigger events to your input.
The only way you would get onchange to work is if you manually trigger onchange in Javascript. A quick example of this:
<form name="f" onsubmit="document.f.h.value='1';
document.f.h.onchange();
return false;"
>
<input type="hidden" name="h" value="0" onchange="alert(document.f.h.value);" />
<input type="submit" />
</form>
Yes, certain browsers (such as Firefox) will fire an onclick or onfocus event on hidden elements when they're activated via an accesskey attribute (meant to provide a keyboard hotkey to jump to an input).
Open the below in firefox, focus the frame, then strike Alt+Shift+x (Windows and Linux) or Ctrl+Alt+x (Mac).
<input type="hidden" accesskey="x" onclick="alert('clicked!');" />
JavaScript has focus events for the elements. There are three focus events: focus, focusin, and focusout.
I discovered focusout will trigger when an element display state is change for both block and none, while focusin only triggered for display state of block.
document.getElementById('element_id').addEventListener('focusout',function(e){
if (this.style.display === "none") {
// perform operations when the element is hidden, like clear fields, etc.
} else {
// perform operations when the element is displayed, like populate fields
}
});
Facing the problem I needed to react on change of hidden inputs which were modified by code which was out of my control, I got inspired by JS onchange hack for input[type=hidden] and created following solution for my problem using MutationObserver
Request:
I want to have function FAM.processFields run whenever any of selected subset of form fields (expressionFields) changes its value.
Problem:
Some of the form fields are of type="hidden", so change event is never fired for them.
Solution:
var index, elementId, element;
var elementIdPrefix = g_form.getTableName() + ".";
var expressionFields = this.getExpressionFieldNames();
// As trigger either Event or MutationRecord is passed, depends on input type
var processFieldsCallback = (function(trigger) {
// Relies on instance of - FAM object - added in onLoad script
FAM.processFields();
});
var changeOfValueConfig = {attributeFilter: ["value"]};
var processFieldsObserver = new MutationObserver(processFieldsCallback);
if (this.debug) {
console.log("addChangeEventListeners to expressionFields");
console.log(expressionFields);
}
for (index = 0; index < expressionFields.length; index++) {
elementId = elementIdPrefix + expressionFields[index];
element = document.getElementById(elementId);
// In case of hidden input (e.g. glideList, fieldList, checkbox) we need to register an observer to it
if (element.getAttribute("type") && element.getAttribute("type").toLowerCase() == "hidden") {
processFieldsObserver.observe(element, changeOfValueConfig);
if (this.debug) {
console.log("register processFieldsObserver of changeOfValueConfig on elementId " + elementId);
console.log(element);
}
}
else {
element.addEventListener("change", processFields);
if (this.debug) {
console.log("addChangeEventListeners on elementId " + elementId);
console.log(element);
}
}
}
Facing the problem I needed to react on change of hidden inputs which were modified by code which was out of my control, I got inspired by JS onchange hack for input[type=hidden] and created following solution for my problem using MutationObserver
Request:
I want to have function FAM.processFields run whenever any of selected subset of form fields (expressionFields) changes its value.
Problem:
Some of the form fields are of type="hidden", so change event is never fired for them.
Solution:
var index, elementId, element;
var elementIdPrefix = g_form.getTableName() + ".";
var expressionFields = this.getExpressionFieldNames();
// As trigger either Event or MutationRecord is passed, depends on input type
var processFieldsCallback = (function(trigger) {
// Relies on instance of - FAM object - added in onLoad script
FAM.processFields();
});
var changeOfValueConfig = {attributeFilter: ["value"]};
var processFieldsObserver = new MutationObserver(processFieldsCallback);
if (this.debug) {
console.log("addChangeEventListeners to expressionFields");
console.log(expressionFields);
}
for (index = 0; index < expressionFields.length; index++) {
elementId = elementIdPrefix + expressionFields[index];
element = document.getElementById(elementId);
// In case of hidden input (e.g. glideList, fieldList, checkbox) we need to register an observer to it
if (element.getAttribute("type") && element.getAttribute("type").toLowerCase() == "hidden") {
processFieldsObserver.observe(element, changeOfValueConfig);
if (this.debug) {
console.log("register processFieldsObserver of changeOfValueConfig on elementId " + elementId);
console.log(element);
}
}
else {
element.addEventListener("change", processFields);
if (this.debug) {
console.log("addChangeEventListeners on elementId " + elementId);
console.log(element);
}
}
}
You can still trigger events on hidden input using labels
The accepted answer claims that: "The user won't be able to trigger events to your input.", but this is not true.
A label connected to an input element can also trigger an input, so even though the input element itself is hidden, if properly connected to a label the user can trigger the input by its label:
There are two ways to connect an input to a label,
Use the id of the input element in the for attribute:
<label for="checkbox">Label</label><input type="checkbox" id="checkbox"/>
Or simply wrap the input inside a label:
<label><input type="checkbox"/>Label</label>
See a working code example here in fiddle or below:
const onChange = (event) => {
console.log(event);
const checkbox = event.target;
alert("checkbox value is: " + checkbox.checked);
}
document.getElementById('checkbox').addEventListener('change', onChange);
input[type="checkbox"] {
visibility: hidden;
}
label {
font-weight: bold;
}
<label>
<input id="checkbox" type="checkbox"/>
label for hidden checkbox
</label>

Categories