Manuel Mauky
Manuel Mauky

Reputation: 2193

change event not triggered with blur() method

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?

Upvotes: 2

Views: 2418

Answers (2)

Robert Todar
Robert Todar

Reputation: 2145

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>

Upvotes: 3

swift-lynx
swift-lynx

Reputation: 3765

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

Upvotes: 3

Related Questions