I've tried searching around for an answer to this, but most of them are outside the context of React, where onChange triggers upon blur.
In performing various tests, I can't seem to tell how these two events are different (when applied to a textarea). Can anyone shed some light on this?
It seems there is no real difference
React, for some reason, attaches listeners for Component.onChange to the DOM element.oninput event. See the note in the docs on forms:
React docs - Forms
There are more people that are surprised by this behavior. For more details, refer to this issue on the React issue tracker:
Document how React's onChange relates to onInput #3964
Quote from the comments on that issue:
I don't understand why React chose to make onChange behave like onInput does. As fas as I can tell, we have no way of getting the old onChange behaviour back. Docs claim it's a "misnomer" but not it isn't really, it does fire when there's a change, just not until the input also loses focus.
For validation, sometimes we don't want to show validation errors until they're done typing. Or maybe we just don't want a re-render on every keystroke. Now the only way to do that is with onBlur but now we also need to check that the value has changed manually.
It's not that big of a deal, but it seems to me like React threw away a useful event and deviated from standard behaviour when there was already an event that does this.
I agree 100% with the comment... But I guess changing it now would bring more problems than it solves since so much code had already been written that relies on this behavior.
React is not part of the official Web API collection
Even though React is built on top of JS, and has seen a huge adoption rate, as a technology React exists to hide a whole lot of functionality under its own (fairly small) API. Once area where this is obvious is in the event system, where there's a lot going on under the surface that's actually radically different from the standard DOM event system. Not just in terms of which events do what, but also in terms of when data is allowed to persist at what stage of the event handling. You can read more about that here:
React Event System
There is no difference
React does not have the behaviour of default 'onChange' event. The 'onChange' which we see in react has the behaviour of default 'onInput' event. So to answer your question there is no difference in both of them in react. I have raised an issue on GitHub regarding the same and this is what they have to say about it:
I think that at the time this decision was made (~4 years ago?), onInput didn’t work consistently between browsers, and was confusing to people coming to the web from other platforms, as they would expect the “change” event to fire on every change. In case of React it is a bigger issue because if you fail to handle change soon enough, the controlled inputs never update, leading people to think React is broken. So the team went with calling it onChange.
In retrospect it might have been a better idea to polyfill onInput and keep its name rather than change the behavior of another event. But that ship has sailed a long time ago. We might revisit this decision in the future, but I would just encourage you to treat it as a quirk of React DOM (which you’ll get used to pretty quickly).
https://github.com/facebook/react/issues/9567
Also this article will provide more insight. As a workaround for default 'onChange' being missing, the article suggests listening to the 'onBlur' event.
https://www.peterbe.com/plog/onchange-in-reactjs
For anyone who stumbled over this issue looking for a way to listen for the actual, DOM-based change event, this is how I did it (written in TypeScript):
import { Component, createElement, InputHTMLAttributes } from 'react';
export interface CustomInputProps {
onChange?: (event: Event) => void;
onInput?: (event: Event) => void;
}
/**
* This component restores the 'onChange' and 'onInput' behavior of JavaScript.
*
* See:
* - https://reactjs.org/docs/dom-elements.html#onchange
* - https://github.com/facebook/react/issues/3964
* - https://github.com/facebook/react/issues/9657
* - https://github.com/facebook/react/issues/14857
*/
export class CustomInput extends Component<Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onInput' | 'ref'> & CustomInputProps> {
private readonly registerCallbacks = (element: HTMLInputElement | null) => {
if (element) {
element.onchange = this.props.onChange ? this.props.onChange : null;
element.oninput = this.props.onInput ? this.props.onInput : null;
}
};
public render() {
return <input ref={this.registerCallbacks} {...this.props} onChange={undefined} onInput={undefined} />;
}
}
Please let me know if you see ways to improve this approach or encounter problems with it. Unlike blur, the change event is also triggered when the user presses enter and is only triggered if the value actually changed.
I'm still gaining experience with this CustomInput component. For example, checkboxes behave strangely. I either have to invert event.target.checked in the onChange handler while passing the value to the checkbox with checked or get rid of this inversion when passing the value to the checkbox with defaultChecked but this then breaks that several checkboxes representing the same state in different places on the page keep in sync. (In both cases, I didn't pass an onInput handler to the CustomInput for checkboxes.)
One difference seems to be that onChange is not fired when selecting and replacing a character with the same character, while onInput is.
See this sandbox: https://codesandbox.io/s/react-onchange-vs-oninput-coggf?file=/src/App.js
Type "A" in the field, then select all and type "B". This will trigger 4 events, 2 onChange and 2 onInput.
Now select all and type "B" again, this till trigger a new onInput event, but no onChange.
As you can see in various comments here, React treats onChange and onInput the same and so, rather than debate the merits of this decision. Here's the solution.
Use onBlur when you don't want to process the user's edits until they're done. :)
Recently I got a bug where onChange would not allow copy and paste in the input field on IE11. Whereas the onInput event would allow that behavior. I could not find any documentation that would describe this in the docs, but that does show there is a difference between the two (expected or not).
The difference is that the oninput event occurs immediately after the value of an element has changed, while onchange occurs when the element loses focus, after the content has been changed.
Related
I'm working with a form that may be a bit over-engineered, and I'm trying to write a script to step through the form and submit it. Most of the form is pretty hackable, but there's a 3-part date input which is just not responding to my attempts to manipulate it programmatically.
The date field works, if I click or tab to it and begin typing. But if I manually dispatch events, even ones that are identical to what it receives when I type and have exactly what the code seems to be looking for, I can't get it to hold onto its values and perform validation. I've tried a lot of variations of this. I've tried manually dispatching a custom event that matches a custom Vue event it should be listening for.
Is there a way to instead manipulate the data of the Vue component directly? To force it to have a certain "monthValue" for example, without intermediate events? I don't expect that there is, but hopefully I'm missing something. Please note that I do have the ability to refactor the form, but that should be an absolute last resort.
As far as I can tell, no, there isn't a way to do this. But it wasn't necessary.
The solution involved being more careful in looking at what the components were actually trying to do. In this case they were input elements using v-model, which is shorthand for a combination of #input (event listener) and :value attributes[1]. This meant that dispatching synthetic input events with the correct data attribute could convince Vue to accept the value and retain it (whereas any value dispatched in any keyboard event would be ignored entirely). This only addressed half of my problem with this particular form, but it is the correct solution for the question asked.
[1] https://vuejs.org/guide/essentials/forms.html
So, it appears that by calling $('#input').val('email#example').change(), it doesn't trigger the React input onChange event.
But this is really necessary for using something like CasperJS for integration testing (filling out a form and submitting, etc.).
So how to do this? I haven't been able to find a solution online or by trying various things in the browser and looking at the React Devtools value of the state.
Here are some related links, that aren't particularly helpful.
Why jQuery.val( value ) does not dispatch any event from the DOM element?
So, to enable the testing, I changed the input from being controlled to being a normal HTML input. For the onSubmit function, I use a ref to find the input value. Couldn't find a way to trigger onChange programmatically.
I am learning Angular 2 from the official guide. I came across the following piece of code.
#Component({
selector: 'loop-back',
template: `
<input #box (keyup)="0">
<p>{{box.value}}</p>
`
})
export class LoopbackComponent { }
As you see in the template keyup event is bound to 0, (keyup)="0". I don't understand what it means when an event is bound to a number. In doc it says that
code binds the keyup event to the number 0, the shortest template statement possible. While the statement does nothing useful, it satisfies Angular's requirement so that Angular will update the screen.
I delved over internet also but could not find any explanation regarding to binding events to number. Can anyone please help me on this? Thanks.
(keyup)="0"
means, when that event happens, then return 0, which is quite equivalent to "do nothing". There is no shorter way of expressing that, except not adding any event binding at all.
The event binding is used in that example to cause change detection to run, which is by default run every time an event handler was called.
Without the event binding, there is no event handler and Angular won't run change detection, which will cause {{box.value}} to not update the value.
It was not clear for me as well, because I thought that Angular triggers the change detection on any asynchronous event. For example Angular University states that:
The following frequently used browser mechanisms are patched to support change detection:
all browser events (click, mouseover, keyup, etc.)
setTimeout() and setInterval()
Ajax requests
But it's not a whole truth, because official documentation says that:
Angular updates the bindings (and therefore the screen) only if the app does something in response to asynchronous events, such as keystrokes. This example code binds the keyup event to the number 0, the shortest template statement possible. While the statement does nothing useful, it satisfies Angular's requirement so that Angular will update the screen.
So apparently an asynchronous event must be handled in the application in order to trigger the change detection, hence (keyup)="0"
Let's say I have a function in a view that triggers when some kind of state is changed.
What would be best to name it and why?
stateChange
stateChanged
onStateChange
onStateChanged
I personally prefer to use onEventName names keeping the native naming convention for DOM event handlers.
Like myElement.onclick = function() { /* ... */ } for click event.
So for myEvent I'm using a handler named onMyEvent.
And if I have event stateChange, then I'll use onStateChange handler.
But really this question is more specific for each team of developers and code-style conventions inside the team/company.
So the main goal in such kinds of questions is to keep the code style the same in all parts to ensure readability.
Therefore if you're working in a team, just keep sticky to the team's code writing conventions and if you're working alone on existing code, try to keep its code style (sure if that style is not obviously ugly).
UPDATE: Understanding.
What is the event? Roughly it's an action initiated outside or inside the program, in other words, something happens in the system, e.g. some state changes (the state of the keyboard, of the mouse, of I/O devices, etc.) doesn't matter how (the user clicked on mouse or some program sent the mouse click signal to the system).
Say the browser window is subscribed to get notifications about some events and the operating system sends them to it as soon as possible, we'll assume that at the same time when something happens. So if the user clicks his mouse when the browser window is active and the document has a focus, the browser says to the document to fire the click event. And here our onclick handler starting its invocation. In other words, the system says to us that now happens a change of some state. And we're handling this change and not handling a fact saying to us that the state has been changed.
Let's assume that our handler is named onClicked. Since the handler's name saying in past tense we can get a reasonable question: "When clicked, how long ago it happened? How many times it was clicked? Hmm, maybe it's too late to handle this action (or actions?) at all...". So this name tells us that something happened sometime in past.
In contrast when our handler is named onClick it's obvious that click event just fired and fired once and we were notified about it immediately. And we're going to handle the click event - the information saying to us that the state of the mouse changed right now (not mouse clicked, but the event of click).
So the names in the past tense are more appropriate for the cases when we need to check if some state has been changed or not. E.g. if the variable stores the state = 1 we can call the function isStateChanged(); which will compare the value in state variable with the real value at the current moment. And here the past tense is a good choice for naming.
onStateChanged because this function triggers whenever some kind of state is changed.
I Googled a few names and noted the number of results returned. You can get some indication of the relative popularity of the most common forms for event handlers:
stateChanged 168k
stateChange 81k [1]
handleStateChange 61k
onStateChange 59k
onStateChanged 12k
beforeStateChange 2k
[1] Results show stateChange used mostly as the name of an event, not a handler.
Using different event types gives a much stronger recommendation towards the onStateChange form:
change [2]
onChange 2000k
onChanged 85k
handleChange 36k
beforeChange 27k
afterChange 22k
click [2]
onClick 48000k
onClicked 58k
handleClick 50k
beforeClick 8k [3]
onDrag 100k
handleDrag 36k
beforeDrag 32k
afterDrag 4k
onDragged 5k
[2] Too many results unrelated to programming.
[3] Apparently certain Microsoft API's can anticipate when the user is going to click.
My bet is for stateChanged due:
stateChange looks like an order, and looks like it receives a param with the new state.
onStateChange and onStateChanged are more keys for storing the handlers not the name for the handler itself.
IMHO
I usually go for a 2 factor event name. As an app grows in size, you may have more than one object who's state changes or perhaps a controller that can broadcast change events for more than one object and would therefore want to be able to differentiate between then both in code and in your head:
Object1:event
Object2:event
As for which event name, I think it comes down to personal preference and consistency.
I think one should make a difference based on the actual moment when the action is happening. For me onStateChange means that it is currently changing and I can be notified about this technically speaking right before the change.
OnStateChanged means the action already happened and I am notified at the end of it.
So, in between onStateChange and onStateChanged there is an important intention difference.
First one says "prepare yourself for this change" while the second one says "it's already happened".
Edit: I got carried away by the intention and didn't realize the naming itself.
Why the on prefix? This is reserved for handlers. The handlers will do something related to (on) that event.
So I would go with stateChange and stateChanged.
I am making mouse click events and I'm trying to dispatch it to some node several times in a row. For that I am using the same MouseEvent object and for some reason this approach does not work. Yet, when I create event manually each time, system works. Does anybody know what is the reason for this behavior?
I've tried to change the timeStamp, but problem still occurs. I can solve the problem like I mentioned before, but I am interested in how this MouseEvent and corresponding dispatching and handling subsystems really work. MouseEvent specification that I've found on MDC pages seems to lack a lot of information.
Tnx for the help!
This is actually a security mechanism, dispatching an event that has been dispatched before isn't allowed. An event always has additional data associated with it, for example whether it comes from a trusted source (user's keyboard rather than JavaScript code). Some attacks (mostly against MSIE because it had mutable event objects) were using this - they caught a trusted event, changed it and dispatched it again elsewhere (changing might not always be required, dispatching it at a different element is enough for some attacks). In the end disallowing redispatching of events turned out to be the best solution. After all, this functionality isn't really required: creating a new event object with identical properties (minus hidden data) isn't exactly hard.
Pretty much all the security issues in this area were related to the file input control. Some time ago Firefox decided to change the file input UI radically and disallow entering the file name directly. I wonder whether this change made redispatching of events a non-issue. I doubt that anybody will be willing to risk opening this can of worms again however.
I think the reason you can't reuse the same MouseEvent object is because the event system maintains some internal state in the event objects so they can implement things like bubbling and cancelling. You may just have to stick with creating distinct event objects.
Reading Document Object Model Events may give you a better understanding of how the DOM event system works.
Without knowing what you have now ill just go under assumption.
Make an event function:
function clickEvent(event) {
//do something
}
Attach it:
obj.onclick = clickHandler;
And you can do this multiple times to multiple objects.