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);
}
Related
<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)}
}
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"))
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 🌹
If I have the following react component:
class Cmpt extends Component {
setValue( e ) {
this.setState({ value : e.target.value });
}
render() {
return <input value={this.state.val} onChange={this.setValue.bind(this)}/>
}
}
Now this works as expected, editing the text doesn't reset the cursor to the end of the input. If I modify it such that the setState happens in async, the cursor reset occurs:
class Cmpt extends Component {
setValue( e ) {
setTimeout( () =>
this.setState({ value : e.target.value }) );
}
render() {
return <input value={this.state.val} onChange={this.setValue.bind(this)}/>
}
}
Obviously the fix is to not call setState synchronously - but I don't understand why the async version doesn't work properly. In my head, the chain of events is as follows:
User adds a character to an input field, changing it from ACD to ABCD
The value of the input DOM node is changed to ABCD to reflect this
Some time passes
setState is called - changing the state of the react component from ACD to ABCD
a render call is triggered - the React diffing algorithm compares the DOM nodes value (ABCD) to the value of this.state.value (ABCD). It sees that both are the same and therefore doesn't trigger a redraw and the cursor is preserved
Clearly my mental model is wrong because a redraw is being triggered - causing the cursor reset.
Please can anyone explain why?
Thanks!
A state changes will always trigger a new render call. After that React itself decides on what to re-render. But it will always get triggered by changing the state. Even if you do
this.setState({})
it will call the render method.
Sorry guys, found a duplicate question that answers my question:
In ReactJS, why does `setState` behave differently when called synchronously?
I can't figure out how to mark my own question as a duplicate unfortunately :(
My mental model of the order of events is wrong. Apparently react triggers a synchronous re-render at the end of every event handler, so render is getting called after the DOM changes, but before the react state has changed - causing a redraw and a cursor reset
Thanks all
T
In looking around to see what ways other developers are handling input focus when working with Redux I've come across some general guidance for ReactJS components such as this. My concern however is that the focus() function is imperative and I could see strange behaviours possible where multiple components are fighting over focus. Is there a redux way of dealing with focus? Is anybody dealing with pragmatically setting focus using redux and react and if so what techniques do you use?
Related:
How to set focus on an element in Elm?
Automatically focus input element after creation in purescript-halogen
https://github.com/cyclejs/cycle-core/issues/153
My approach is using ref callback, which is kind of an onRenderComplete of an element. In that callback I can focus (conditionally, if needed) and gain a reference for future focusing.
If the input is rendered conditionally after an action runs, that ref callback should fire a focus, because the ref doesn't exist yet immediately after calling the action, but only after render is done. Dealing with componentDidUpdate for things like focus just seems like a mess.
// Composer.jsx -- contains an input that will need to be focused somewhere else
class Composer extends Component {
render() {
return <input type="text" ref="input" />
}
// exposed as a public method
focus() {
this.refs.input.focus()
}
}
// App.jsx
#connect(
state => ({ isComposing: state.isComposing }),
...
)
class App extends Component {
render() {
const { isComposing } = this.props // or props, doesn't matter
return (
<div>
<button onClick={::this._onCompose}>Compose</button>
{isComposing ? <Composer ref={c => {
this._composer = c
this._composer && this._composer.focus() // issue initial focus
}} /> : null}
</div>
)
}
_onCompose() {
this.props.startComposing() // fire an action that changes state.isComposing
// the first time the action dispatches, this._composer is still null, so the ref takes care of the focus. After the render, the ref remains so it can be accessed:
this._composer && this._composer.focus() // focus if ref already exists
}
}
Why not autoFocus or isFocued prop?
As HTMLInputElement has value as a prop, but focus() as a method -- and not isFocused prop -- I would keep using methods to handle that. isFocused can get a value but if the user blurs from the input, what happens to that value? It'll be out of sync. Also, as mentioned in the comments, autoFocus can conflict with multiple components
So how to decide between props and methods?
For most cases props will be the answer. Methods can be used only in a 'fire and forget' things, such as scrollToBottom in a chat when a new message comes in, scrollIntoView and such. These are one time behaviors that the store doesn't care about and the user can change with an interaction, so a boolean prop won't fit. For all other things, I'd go with props.
Here's a jsbin:
http://jsbin.com/waholo/edit?html,js,output