How to trigger onChange with casperjs and React? - javascript

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.

Related

Is there a way to use vanilla JS to manipulate data in a Vue component?

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

how can change an event behavior like another event? [duplicate]

I'm trying to simulate an actual tab key press in JavaScript. I don't want to focus on the next element or anything like that, I just want to make it seem like the tab key has been pressed.
The reason why is because I am building a form JavaScript class where I want to be able to use the enter key just like tab. If someone is using a native BROWSER autocomplete, I need to fire the tab key to capture the selected autocomplete response. If I just move to the next input it won't capture their autocomplete selection and leave the field blank.
Any thoughts?
I don't think it's possible; an article about DOM events here ...mentions that firing an event doesn't trigger the default result of the user action, for security reasons; the script should not be able to simulate user interaction directly. You will have to simulate the behavior the keypress causes (such as focus on a field), instead of trying to actually simulate a keypress. You probably won't be able to interact with the browser's native autocomplete functionality, unless the browser explicitly provides a means for you to do so.
Edit:
See also: [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autocomplete] (Autocomplete HTML attribute)

How to use Jquery to update textarea value in react app

I'm building a Chrome extension that layers over a 3rd party react website. I am attempting to update the value of a textarea within that app using the following code:
$('textarea').val("Text to go in textarea.");
The code successfully updates the textarea however once the user clicks on the textarea, the DOM seems to regenerate and the value becomes blank.
What is the best way to update the value within the textarea so that it remains even once the user clicks and DOM regenerates? I am not a react expert however my guess is that the textarea is tied to the state. Is there any way to update that from my own jquery within my chrome extension?
Just to be clear, the textarea belongs to a 3rd party website/react app that I have no control over. I'm trying to manipulate it from my own google chrome extension. I thought the easiest way would be to somehow simulate actual typing in order to make the react app think the user typed my input however I searched around and could not find a way to do that.
Expanding on #Panther's suggestion, you can set the value as you have done above and then trigger the onChange or keypress event etc to save the changes in either state or props. Now since React uses synthetic events , you need to trigger then as shown.
$('textarea').val("Text to go in textarea.");
$.each(document.getElementsByTagName("textarea"),(index,Element)=>{
let event = new Event("change"); // repeat for keypressup,down,input etc.
Element.dispatchEvent(event);
});
Try to use set value of DOM Html element:
document.getElementById("textarea").value = "Johnny Bravo";

In React, what's the difference between onChange and onInput?

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.

Detecting a change in radio button/checkbox state

I need to reliably detect the state change of radio buttons/checkboxes on my page in order to watch if the form was modified or not. Now, this is a completely separate script, I cannot modify anything that controls the form.
Right now, I can see only two ways of doing this:
onchange event handler, which helps with textboxes, textareas and selects, but is not fired for checkboxes/radiobuttons
onclick event handler, which is not reliable, because users often use hotkeys to change the values of these elements.
What am I missing here? Is there a way to reliably detect that checkbox was checked/unchecked?
UPDATE: As you guys pointed out, change event is really fired on checkboxes/radiobuttons, despite the fact that w3schools says it is only for text inputs
However, my problem turned out to be that the values of checkboxes/radiobuttons are set via setAttribute in scripts and in that case the event is not fired.
Is there anything I can do in this case?
See: http://www.quirksmode.org/dom/events/change.html.
It says that all major browsers support change event but the IE's implementation is buggy.
IE fires the event when the checkbox or radio is blurred, and not when it is activated. This is a serious bug that requires the user to take another action and prevents a consistent cross-browser interface based on the change event on checkboxes and radios.
I think you can overcome IE's bug with this trick. blur() elements when they focued! (Use something like $('input[type=radio]').focus(function(){$(this).blur();}); in jQuery or use pure javascript)
Ok, after some digging, here is what I found out. Note, this is applicable to Firefox, and, probably to Firefox only. Since in this case I was dealing with internal application, this was enough for me.
So, basically, in order to reliably detect changes in checkbox/radiobutton state in Firefox, you need to do two things:
Set up custom Firefox's event handlers CheckboxStateChange and RadioStateChange for checkbox and radiobutton respectively. These events will be fired when the user changes the inputs or when it is modified via script, using setAttribute, however, these events are not fired, when the state is changed in the script, using checked or selected properties of these elements, this is why we need ...
Watch the changes of the checked property using Object.watch
Standard onchange event is no good, since it only fired when user changes the value directly.
Damn, this thing is broken...
If people get interested, I'll post some code.

Categories

Resources