React checkbox: onChange vs onClick with readOnly [duplicate] - reactjs

<input type="checkbox" onclick="onClickHandler()" onchange="onChangeHandler()" />
From within onClickHandler and/or onChangeHandler, how can I determine what is the new state of the checkbox?

The short answer:
Use the click event, which won't fire until after the value has been updated, and fires when you want it to:
<label><input type='checkbox' onclick='handleClick(this);'>Checkbox</label>
function handleClick(cb) {
display("Clicked, new value = " + cb.checked);
}
Live example | Source
The longer answer:
The change event handler isn't called until the checked state has been updated (live example | source), but because (as Tim Büthe points out in the comments) IE doesn't fire the change event until the checkbox loses focus, you don't get the notification proactively. Worse, with IE if you click a label for the checkbox (rather than the checkbox itself) to update it, you can get the impression that you're getting the old value (try it with IE here by clicking the label: live example | source). This is because if the checkbox has focus, clicking the label takes the focus away from it, firing the change event with the old value, and then the click happens setting the new value and setting focus back on the checkbox. Very confusing.
But you can avoid all of that unpleasantness if you use click instead.
I've used DOM0 handlers (onxyz attributes) because that's what you asked about, but for the record, I would generally recommend hooking up handlers in code (DOM2's addEventListener, or attachEvent in older versions of IE) rather than using onxyz attributes. That lets you attach multiple handlers to the same element and lets you avoid making all of your handlers global functions.
An earlier version of this answer used this code for handleClick:
function handleClick(cb) {
setTimeout(function() {
display("Clicked, new value = " + cb.checked);
}, 0);
}
The goal seemed to be to allow the click to complete before looking at the value. As far as I'm aware, there's no reason to do that, and I have no idea why I did. The value is changed before the click handler is called. In fact, the spec is quite clear about that. The version without setTimeout works perfectly well in every browser I've tried (even IE6). I can only assume I was thinking about some other platform where the change isn't done until after the event. In any case, no reason to do that with HTML checkboxes.

For React.js, you can do this with more readable code. Hope it helps.
handleCheckboxChange(e) {
console.log('value of checkbox : ', e.target.checked);
}
render() {
return <input type="checkbox" onChange={this.handleCheckboxChange.bind(this)} />
}

Use this
<input type="checkbox" onclick="onClickHandler()" id="box" />
<script>
function onClickHandler(){
var chk=document.getElementById("box").value;
//use this value
}
</script>

use onclick event on all checkboxes that you want to get their values whether they are checked or not.
<input type="checkbox" value="rightSideCheckbox" onclick='handleClick(this);'>
function handleClick(checkbox) {
if(checkbox.checked){
console.log(checkbox.value+"True")
}
else{
console.log(checkbox.value+"False")
}
}

const [checkboxval, setCheckboxVal] = React.useState(null);
const handleChangeCheckbox = (e) => {
setCheckboxVal(e.target.checked);
}
render() {
return <input type="checkbox" onChange={(e) => handleChangeCheckbox(e)}
}

Related

Launch keyboard event from React ref

I have a React component that has an input element with an attached ref. I am aware of the common: inputRef.current.focus(); usage of a ref to focus a text input. But, I am struggling to find a good solution to dispatch a certain keyboard event from inputRef.current. I have tried:
let downEv = new KeyboardEvent('keydown', {'keyCode': 40, 'which': 40});
inputRef.current.dispatchEvent(downEv);
But, that doesn't seem to do anything.
KeyboardEvent is a native browser event (which is different than React's Synthetic event) hence you need to add a native listener as well like below in order to listen to them. example on csb
useEffect(()=>{
ref.current.addEventListener('keydown',handleKeyDown)
},[ref])
It's possible to do this, and not need to use ref.
You can try isolating what you want to trigger by doing this:
handleKeyPress = (e) => {
if (e.keyCode === 40) {
// Whatever you want to trigger
console.log(e.target.value)
}
}
<input onKeyPress={handleKeyPress} />
You can also trigger this from a form if you prefer:
<form onKeyPress={handleKeyPress}>
...
</form>

Checkbox/Radio onChange event not returning the standard event object (Only if React-plus-Carbon)

I'm just starting with React, combined with the Carbon Design System from IBM (https://www.carbondesignsystem.com/). My problem is that Checkbox and RadioButton components do not return the same {event} object to my onChange handler as that returned by straight React/JSX. Carbon DOES match React on TextInput and Select components.
The behavior is similar to the issue in React onChange event doesnt return object. However, that is referencing React Toolbox and Material Design, which I am not using.
The difference can be seen in Carbon's online sandbox tool. An example of a radio button is at http://react.carbondesignsystem.com/?selectedKind=RadioButton&selectedStory=Default&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel. Click the button and see the results returned in the Action Logger panel. Compare to results of changing (not just clicking) a text input in http://react.carbondesignsystem.com/?selectedKind=TextInput&selectedStory=Default&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel. The problem element returns {event} as the third element down, while the good one returns only one element containing the {event} as desired. Apparently, Carbon is only passing along the first element.
Below is the change handler, the ReactJSX, and the resulting HTML.
handleChange(event) {
console.log(event)
const {name, value, type, checked} = event.target
this.setState({[name]: value})
}
<RadioButton
id="gender-male"
name="gender"
labelText="Male (Carbon)"
labelPosition="right"
value="male"
checked={this.state.gender === "male"}
onChange={this.handleChange}
/>
<div class="bx--radio-button-wrapper">
<input
id="gender-male"
name="gender"
type="radio"
class="bx--radio-button"
value="male"
>
<label for="gender-male"
class="bx--radio-button__label"
aria-label="Male (Carbon)">
<span class="bx--radio-button__appearance"></span>
<span class="">Male (Carbon)</span>
</label>
</div>
The expected behavior is for Local Scope to contain an event object with properties for name, value, type, checked, etc. But for Carbon's RadioButton and Checkbox, Local Scope contains only a flat text of the element's value, no object at all.
Global Scope does seem to contain the full object. But I hesitate to reference outside of Local, and it seems wrong to have to.
The following code is straight from the RadioButton component of the carbon-components-react library.
handleChange = evt => {
this.props.onChange(this.props.value, this.props.name, evt);
};
source
The code shows that the event is passed as the third argument, following the contents of the value and name props of the RadioButton component.
So you should be able to handle changes like this:
handleChange(value, name, event) {
console.log(event)
const {type, checked} = event.target // Should not be needed anymore.
this.setState({[name]: value})
}

change value of input made with react from chrome extension

I work on Chrome extension, i need to update lot of inputs of an html page made with React from numbers readed from CSV. I cannot update the web site.
-
An example of input copied from the rendered website :
<td><input class="input input_small fpInput" value="29,4"></td>
-
How it's made (not sure 100% about that, had to read the uglified js source)
{
key: "render",
value: function () {
return s.a.createElement("input", {
className: "input input_small fpInput",
value: this.state.value,
onChange: this.handleChange,
onBlur: this.handleSubmit,
onFocus: this.handleFocus
})
}
}
-
Each time you change the input value a function is called and a POST is made to save it.
I want to trigger the onBlur() or onChange() from my extension after i changed the input value to trigger the POST
I tried this :
var el = document. ... .querySelector('input'); // the selector is simplied of course
el.value = 321;
el.onChange(); // ERROR onChange is not a function
el.onchange(); // ERROR onchange is not a function
el.handleChange(); // ERROR handleChange is not a function
Any idea please ?
You can't call a React component's method directly from the DOM element it has rendered. You need to trigger an event that bubbles up so that React can catch it at the document level and process it normally, as it would do with a real one.
✨ Document.execCommand():
As pointed out by #woxxom in the comments, the easiest way to do that might be to focus the inputs and then use Document.execCommand():
const input1 = document.getElementById('input1');
const input2 = document.getElementById('input2');
input1.focus();
document.execCommand('insertText', false, 'input1');
input2.focus();
document.execCommand('insertText', false, 'input2');
<input id="input1" />
<input id="input2" />
⚒️ Manually Dispatching Events:
Otherwise, you might try manually dispatching a change, input and/or blur event using the Event() constructor in those fields after you change their value.
Also, note Event()'s second optional argument contains a field, bubbles, that is false by default. You need that one to be true. Otherwise, this won't work, as React is listening for events on the document.
Additionally, you might need to use Element.setAttribute() too, as that will update the value attribute on the DOM (the initial value on the field), while element.value will update the current value (and so the display value). Usually, though, it's not needed. For more on this see What is the difference between properties and attributes in HTML?.
This approach might have some timing issues you might need to handle using setTimeout when updating multiple inputs, so if the first one works, I'd go for that one instead.
const input1 = document.getElementById('input1');
// This updates the value displayed on the input, but not the DOM (you can do that with setAttribute,
// but it's not needed here):
input1.value = 'input1';
// Dispatch an "input" event. In some cases, "change" would also work:
input1.dispatchEvent(new Event('input', { bubbles: true }));
// It looks like only one field will be updated if both events are dispatched
// straight away, so you could use a setTimeout here:
setTimeout(() => {
const input2 = document.getElementById('input2');
input2.value = 'input2';
input2.dispatchEvent(new Event('input', { bubbles: true }));
});
<input id="input1" />
<input id="input2" />
To elaborate a bit more on #varoons answer, which is factually correct albeit a bit short on explanation.
You can do so by injecting (dispatching, in browser terms) the event into the dom:
// Needs setAttribute to work well with React and everything, just `.value` doesn't cut it
// Also changed it to a string, as all attributes are strings (even for <input type="number" />)
el.setAttribute("value", "321");
// As #wOxxOm pointed out, we need to pass `{ bubbles: true }` to the options,
// as React listens on the document element and not the individual input elements
el.dispatchEvent(new Event("change", { bubbles: true }));
el.dispatchEvent(new Event("blur", { bubbles: true }));
This will actually call all the listeners, even those made with React (as is the case in your de-uglyfied code ;)) or made with simple element.onChange = () => {...} listeners.
Example: https://codesandbox.io/s/kml7m2nn4r
el.dispatchEvent(new CustomEvent("change"))

Using onBlur to set focus in a React component

I've attached an onBlur event handler in a React component in which the logic sets the focus back to the target element (and writing this in TypeScript).
emailBlur(e: React.FocusEvent<HTMLInputElement>) {
e.currentTarget.focus();
e.preventDefault();
// re-ordering these statements makes no difference
}
This is bound
<input type="email" onBlur={this.emailBlur} />
Furthermore, the constructor contains
this.emailBlur = this.emailBlur.bind(this);
But the focus never gets set - if I click from the target element to another element, the focus never goes back to the target element.
Why isn't the focus being set back to the target element?
Have you tried using e.currentTarget and a timeout like this?
e.preventDefault();
const target = e.currentTarget;
setTimeout(
function () {
target.focus();
},
5
);
Why isn't the focus being set back to the target element?
Use setTimeout so the blur completes before you focus again 🌹

Bubble is not firing when programmatically Input changed

Having an Input from semantic-ui-react changed when the User writes something, does fire onChange and any parent component that includes the Input fires onChange as well. A process called bubble .... right?
Example
<li onChange={this.onListChange}>
<Input onChange={this.onInputChange}/>
</li>
Any change made in the Input, fires onInputChange() and onListChange() together one after another.
Although, when Input.value/text/content is changed dynamically, Input.onChange() is not called at all. So you have to call the onChange() function manually.
setFoo() {
this.input.value = 'foo';
this.inputChange();
}
But the problem here is, that when we call inputChange we don't get as e.target the component Input, nor data has anything to do with it, and the most important ... :
No Bubbling effect.
Which means that onListChange() will not be fired.
Question:
How can I achieve a proper bugless bubbled onChange() on Semantic-UI-React?
Not exactly sure about semantic-ui-react because I've never used it, but this in theory should work (it works for a normal input):
setFoo() {
this.input.value = 'foo';
const event = new Event('input', { bubbles: true });
this.input.dispatchEvent(event);
}

Resources