When a user types something in an <input type="text"> and removes the focus, both blur and change are fired.
However, when I do the same thing in JavaScript using the blur() method, only the blur event is fired and not the change event. Is there a reason for this inconsistency?
See this example code (jsfiddle):
<input type="text">
<button>Test</button>
const input = document.querySelector("input")
input.addEventListener("blur", () => console.log("blur"))
input.addEventListener("change", () => console.log("change"))
const button = document.querySelector("button")
button.addEventListener("click", () => {
setTimeout(() => {
input.focus()
input.value = "something"
input.blur()
}, 1000)
})
When clicking the button, after a second, it should focus the input, change the value and blur the input. However, only the blur event is fired. Doing the same by hand will fire both events.
I like to trigger some validation logic on the change event and it works perfectly fine in real-live but when I try to recreate the workflow in a unittest it fails and I'm not sure why and how to solve it.
So the alternative question is: How can I trigger the change event from JavaScript?
This issue
The change event is specifically emitted when a user interacts with an element. This is built in a was intentional. #see HTMLElement: change event.
The solution
Use synthetic events to mimic user interaction in changing the value: input.dispatchEvent(new Event("change"));
Below is a working example with the logic in its own function updateValueWithChangeEvent .
const input = document.querySelector("input")
input.addEventListener("blur", () => console.log("blur"))
input.addEventListener("change", () => console.log("change"))
// Updates the value of an input and triggers the change Event.
const updateValueWithChangeEvent = (input, value) => {
if (input.value === value) return
input.value = value
input.dispatchEvent(new Event("change"));
}
// Updated example using function above
const button = document.querySelector("button")
button.addEventListener("click", () => {
setTimeout(() => {
// This will update value and trigger change event
updateValueWithChangeEvent(input, "something")
// This will trigger the blur event
input.focus()
input.blur()
}, 1000)
})
<input type="text">
<button>Test</button>
You can trigger an event like this:
const input = document.querySelector("input");
const event = new Event("change");
// blur the input
input.blur();
// dispatch change event manually
input.dispatchEvent(event);
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
Related
I'm trying to action a function when either a button is clicked or the spacebar is pressed.
I have this working to some degree but it's not how I want it.
Here's my function:
const showText = () => {
const x = ToughSpellings.toString();
console.log(x);
}
Here's my button and spacebar actions:
<input type="text" id="one" onKeyUp={showText} />
<button onClick={showText}>Show Next Letter</button>
I cannot work out how to use onKeyUp without an input field. How can I use this function when the user is simply looking at the website?
Without using an input field, you'd need to setup a document event listener to listen for keyboard events.
You could have the following code in your React component:
const keyDownHandler = (event) => {
console.log(event.keyCode); // Key UP would return `38`
// Handle key event here based on `event.keyCode`
};
useEffect(() => {
document.addEventListener("keydown", keyDownHandler);
return () => document.removeEventListener("keydown", keyDownHandler);
}, []);
In my react application, I have blur event listener, in my listener function I want to know, on which the focus went to. How can I get to know that in chrome browser?
The below is my onBlur event function
const handleBlurOfDateInput = (date, event) => {
const valueEntered = datetoMomentDate(date);
// Here i want to check, which element got focused using event
hide && hide();
onChange(valueEntered);
};
You can use event.target, or document.getElementFromPoint(event.pageX, event.pageY)
const handleBlurOfDateInput = (date, event) => {
const valueEntered = datetoMomentDate(date);
// Here i want to check, which element got focused using event
hide && hide();
onChange(valueEntered);
};
const handleBlurOfDateInput = (date, event) => {
const valueEntered = datetoMomentDate(date);
if(event.relatedTarget){console.log(event.relatedTarget)}
hide && hide();
onChange(valueEntered);
};
You can use relatedTarget.
Notice that relatedTarget will return null if the element focused is not an input. In this case, you can use tabIndex = '0' for that element.
I have an input field with a JS focusout event. Under my input field, I have an autocomplete popup with suggestions. But when I click on a suggestion, it’s playing the focusout before the event listener on the click of the autocomplete! Any clues on how I can I fix this conflict?
Picture of the input and its autocompletion:
The click event:
resultsFrom.addEventListener('click', (event) => {
let e;
e = event.target.parentNode;
inputFrom.value = e.getAttribute('data-display');
});
The focusout event:
inputFrom.addEventListener('focusout', () => {
const list = document.querySelector('#results-from');
let first = list.firstChild;
inputFrom.value = first.getAttribute('data-display');
resultsFrom.innerHTML = '';
});
The focusout event has a property on the event object of relatedTarget - this is the element that's going to gain the focus, in this case, it will be the element you're clicking on.
You need to check if that element is within your results, and not clear them out if that's the case. Something like this:
inputFrom.addEventListener('focusout', (e) => {
const list = document.querySelector('#results-from');
if (!list.contains(e.relatedTarget)) {
//the target is not in the list, continue as before
//otherwise allow the click to function by not clearing out resultsFrom
let first = list.firstChild;
inputFrom.value = first.getAttribute('data-display');
resultsFrom.innerHTML = '';
}
});
I have an #Html.TextBoxFor as below :
#Html.TextBoxFor(u => u.SomeProperty, new { #class = "jtb", #id = "TrajName", placeholder = "Traj Name" })
Now what I want to achieve is I want to know when a new character is added to this textbox at the same time it is entered.
I want to change a button state to active at this time. I tried blur and change event. But it is fired only when the focus changes.
$(document).ready(function () {
$('#TrajName').val("");
$('#StartLocation').val("-Select Location-");
$('#EndLocation').val("-Select Location-");
document.getElementById("BtnAddTraj").disabled = true;
$("#TrajectoryName").blur(function () {
if ($('#TrajName').text != "")
document.getElementById("BtnAddTraj").disabled = false;
else
document.getElementById("BtnAddTraj").disabled = true;
});
});
I have a scenario where user can directly try to click on the button after entering some text(ie cursor still inside textbox and focus is not changed).
So is there any event that gives live trigger when a character is added instead of firing on focus change?
You need to bind an event handler to the keyup JavaScript event.
Further more, I recommend you to use .prop for set disabled property.
Please try this:
#Html.TextBoxFor(u => u.SomeProperty, new { #class = "jtb", #id = "TrajName", placeholder = "Traj Name" })
$("#TrajectoryName").keyup(function () {
if ($('#TrajName').val() != "")
$("#BtnAddTraj").prop('disabled',false);
else
$("#BtnAddTraj").prop('disabled',true);
});
Another solution is to trigger the input event to the TrajectoryName textbox. This would fire every time your input changes.
$("#TrajectoryName").on('input',function () {
if ($('#TrajName').val() != "")
$("#BtnAddTraj").prop('disabled',false);
else
$("#BtnAddTraj").prop('disabled',true);
});
I have an input text that get his value from a Javascript function (a timer with countdown).
I want to raise an event when the input text is 0 ,so I am using the change eventListener.
Unfortunately it doesn't seem to raise the event when the change is coming from javascript function.
How can I force the change event to work, even if the change is coming from Javascript and not from the user?
From the fine manual:
change
The change event occurs when a control loses the input focus and its value has been modified since gaining focus. This event is valid for INPUT, SELECT, and TEXTAREA. element.
When you modify the text input's value through code, the change event will not be fired because there is no focus change. You can trigger the event yourself though with createEvent and dispatchEvent, for example:
el = document.getElementById('x');
ev = document.createEvent('Event');
ev.initEvent('change', true, false);
el.dispatchEvent(ev);
And a live version: http://jsfiddle.net/ambiguous/nH8CH/
In the function that changes the value, manually fire a change event.
var e = document.createEvent('HTMLEvents');
e.initEvent('change', false, false);
some_input_element.dispatchEvent(e);
it's 2018 now and seems that initEvent() is deprecated:
https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent
i think you can trigger the event in a one-liner now:
element.dispatchEvent(new Event('change'));
A more reusable option :
function simulate_event(eventName, element) {
// You could set this into the prototype as a method.
var event;
if (document.createEvent) {
event = document.createEvent("HTMLEvents");
event.initEvent(eventName, true, true);
} else {
event = document.createEventObject();
event.eventType = eventName;
};
event.eventName = eventName;
if (document.createEvent) {
element.dispatchEvent(event);
} else {
element.fireEvent("on" + event.eventName, event);
}
};
Simply redefine the "value" property of the node, using getAttribute("value") and setAttribute("value", newValue), in the getters and setters, as well as dispatch the "change" event at the end of the setter. For example:
myNode.onchange = e => console.log("Changed!", e.target.value);
Object.defineProperty(myNode, "value", {
get: () => myNode.getAttribute("value"),
set(newValue) {
myNode.setAttribute("value", newValue);
myNode.dispatchEvent(new Event("change")); //or define the event earlier, not sure how much of a performance difference it makes though
}
})
var i = 0;
setTimeout(function changeIt() {
if(i++ < 10) {
myNode.value = i;
setTimeout(changeIt, 1000);
}
}, 1)
<input id="myNode">
Instead of using change, you can use keypress event instead.
This is because the change event is not meant to fire until it is not focused anymore - when you click out of the input tag.