Input form - change the running order of onChange and isDisabled - javascript

I have implemented in React a webpage with 3 input fields, each one with the properties of
onChange={this.handleChange} and disabled={this.isDisabled()}
The desired behavior is that when an input field contains 2 digits, the focus will be moved to the next input field.
As long as the field doesn't contain 2 digits, the fields next to must be disabled.
What actually happens, when I type the second digit in the first field, it runs the handleChange function, that function checks whether the field contains 2 digits, find out that yes, and moves the focus to the next input field.
But the next field is disabled! (because the isDisabled function didn't run yet!)
So the cursor doesn't move..
I want to change the order of the happenings, or any other way to solve it.
Do you have any suggestions?

The problem is that this.isDisabled() runs immediately in render but this.handleChange runs on click and most possibly doesn't change the state thus no rerender.
You sholdn't run function on next input, you should pass true or false to its disabled prop. Just make handleChange update the state which defines which fields are disabled. And pass that state to your inputs accordingly.

I had faced the same issue a few days back. My approach was however using react states and focusing the input by its id, that was fetched from state;
So first we make a input - id map for our convenience. And use document.getElementById(this.state.active).focus() function. We change our state via our change handler.
render() {
this.setInputFocus();
return (
<div className="App">
<input id="1" onChange={this.onChange} />
<input id="2" onChange={this.onChange} />
<input id="3" onChange={this.onChange} />
</div>
);
}
setInputFocus = () => {
if (document.getElementById(this.state.active)) {
document.getElementById(this.state.active).focus();
}
};
onChange = e => {
if (e.target.value.length === 2) {
this.setState({ active: this.state.active + 1 });
}
};
Here is a full code that somewhat solves the issue

Related

Set Form data from sub components

im currently trying to create an dynamic form that uses a sub component to render out some input fields as createing them static would exceed a limit. I pass the states for the the form i made aswell as some date and the change form. But when i render the form as it does so fine! as soon as i change the state its sends a warning about uncontrolled components that you can read about it here
I have tried pre-setting all the fields with empty defaults but it doesnt help.
Am i doing it somewhat correct or totally wrong? or what is the correct way, or what am i doing wrong. thanks in adbance.
As for the code looks like this:
Edit.js
export default function InventoryItemEdit() {
const [form, setForm] = useState({});
function handleFormChange(e) {
setForm({ ...form, [e.target.name]: e.target.value });
}
const variants = (
<ItemVariants
form={form}
onChange={handleFormChange}
fields={form.sizes}
/* ^^ fields data fetched from the server i set via use effect hook when loading the page */
/>
);
const updateItem = async (event) => {
event.preventDefault();
/* Do form submit post */
};
return (
<form onSubmit={updateItem}>
<div>
<p htmlFor="name">Name</p>
<input
id="name"
name="name"
onChange={handleFormChange}
value={form.name}
type="text"
required
placeholder="Name of Item"
/>
</div>
{variants}
</form>
);
}
As for the sub component ItemVariants it looke like this
ItemVariants.js
export default function ItemVariants({
form = {},
onChange = '',
fields = [],
}) {
return (
<>
{fields.map((row, index) => (
<div>
<span>
{row.name}
</span>
<input
type="text"
id={`variant${index}`}
name={`variant${index}`}
onChange={onChange}
value={form[`variant${index}`]}
required
min="0"
placeholder="0"
defaultValue="0"
/>
</div>
))}
</>
);
}
Controlled component: is when your input value is coming from a single source of truth a state(meaning for an input value to change, you need to update the state holding the value)
Uncontrolled component: is when your input value is not coming from a state but rather it's coming from something we call useRef/createRef which helps to reference to react syntactic DOMNODE thus giving us the ability to interact with input in a false-actual-DOM(as if we were query an actual DOM input-node in pure-JS). Meaning if your input value is not coming from a state, it must come from a ref(ref.current.value which is equivalent to document.querySelector(theInputLocator).value).
Answer to your bug: I see that everything is okay, but the only issue is that you didn't set the initial state with the name key. Thats an analysing issue because in your code you doing [e.target.name]:e.target.value and the way inputs works generally is that event is triggered but must recent value is emitted when the event happens next. it works like a++.
Do this:
const [form, setForm] = React.useState({ name: '' });
The general rule of thumb is that always describe your form input keys when your inputs are predefine and not dynamic(in this case your name input is predefined).
So After digging reading this post i have to thank! #juliomalves for solution with value={form[`variant${index}`] ?? ''} or value={form[`variant${index}`] || ''}
I also found out i was accidently adding defaultvalue aswell as value which cannot be set at the same time i found out. After i tested it removed the default value and set it correctly to be a string! it now works like a charm!
Also thanks to #Emmanuel Onah for the explaination it really helped me understand more about the react states!
Thanks again for everyone that helped

How to not clear input field onClick

I'm working with React JS and I want to make a hidden button for a text box, of type "Row", such that when I click onto that box, a description will appear on the side, the Row has this structure
<div>
<form key={id}>
<button
className="name"
type="submit"
onClick={clickFunc}
>
{data.text}
</button>
</form>
</div>
Where clickFunc makes a call to enterMouseFunc, a function passed in when called in another component file:
const clickFunc = useCallback((e) => {
e.preventDefault();
enterMouseFunc(e, data);
});
In the description box, there is an input field,
// some other details here
<form key={id} onClick={inputClick}>
<input
type="text"
className="inputParam"
name={id}
onChange={handleChange}
/>
<button
type="submit"
style={{ display: "none" }}
></button>
</form>
My inputClick:
const inputClick = (e) => {
e.preventDefault();
};
My handleChange:
const handleChange = (e) => {
e.preventDefault();
setParameters({ name: e.target.name, value: e.target.value });
};
Which works just fine. However, whenever I click on the Row again, or switch between other Rows, all user's inputs get cleared up. The page doesn't refresh since I already suppress this behavior, but the inputs still get deleted. How to stop it from clearing up the inputs all the time?
Edit:
This is how the interface looks like, where the grey boxes are of type Row. When we click on these boxes, the description will appear on the right as shown:
Are you by any chance triggering the onSubmit of the form? You prevent the inputClick but do not prevent the submit. However, im not sure it would be invoked. Why have a hidden submit button at all?
Does setParameters contain all of the fields values? If so you should copy the existing values before reassigning name and value. If not the issue is elsewhere.
A fix would look like this if that is the case:
const handleChange = (e) => {
e.preventDefault();
setParameters({...parameters, name: e.target.name, value: e.target.value});
};
Unless you would like to submit the form, then you don't necessarily need a <form> element?
Also, having a click event handler on that element (instead of say, a button) is not really common, I am not totally surprised that it causes side effects.
What I would do is remove forms that do not submit: just the standalone inputs that trigger setState/setReducer on change events.
Then you should be able to remove hidden buttons, preventDefault calls, etc.
About the cleaning of the values, I suspect your id value in the key prop to change, which would cause a re-mount of the form children.

React/Next.js how to get other Element event target value on button click

I have an input element and a button in React:
<li><input type="text" placeholder="Enter new ID"></input>
<button onClick={(e)=>this.saveKonfigElementHandler()}>Save</button></li>
Now, when I enter some value into the input field, I want to save the value into some array when I click on the button.
Is it somehow possible to get a reference to that input field (e.g. the target.value of the input field) to save it when clicking the button?
Or would I simply have to do it with an onChange event that saves the current input value into some Variable, and when I click the button, I will simply retrieve that value to save it into some array? Maybe that would be a lot simpler.
E.g:
<input type="text" value={this.state.inputFieldText.join('')} onChange={(event) => this.textHandler(event)}></input>
in the textHandler Method, I will save the target value from the input field into a Class Component state variable in the textHandler() method. And when I click the button, I retrieve that state value and can do some manipulation with it?
A modern way to do it, with function components, hooks and a controlled form element, is:
import { useState } from 'react'
function MyComponent({ initialId, onSave }) {
const [newId, setNewId] = useState(initialId)
return (
<li>
<input
type="text"
placeholder="Enter new ID"
onChange={(e) => setNewId(e.target.value)}
/>
<button onClick={() => onSave(newId)}>Save</button>
</li>
)
}
I'd also note that it is considered better accessibility practice to use a label element for describing the purpose of your field, rather than a placeholder. Placeholders are more appropriate for example input.
Is it somehow possible to get a reference to that input field (e.g. the target.value of the input field) to save it when clicking the button?
Yes.
Or would I simply have to do it with an onChange event that saves the current input value into some Variable, and when I click the button, I will simply retrieve that value to save it into some array? Maybe that would be a lot simpler.
That would be a slightly more React way to do it.
Your DOM-only approach is more "uncontrolled" (see these docs for what controlled/uncontrolled means). You'd do it like this:
Change your onClick to pass e to the handler:
onClick={(e)=>this.saveKonfigElementHandler(e)}
In saveKonfigElementHandler, use e.target.previousElementSibling to access the input:
saveKonfigElementHandler(e) {
const { value } = e.target.previousElementSibling;
// Use `value` ...
}
That's fragile, of course; if you change your structure so another element is between the button and the input, or the input is within a container element, etc., it'll break — which is one argument for the controlled approach. You could store a link to the input in a data attribute on the button:
<li><input id="id-input" type="text" placeholder="Enter new ID"/>
<button data-input="#id-input" onClick={(e)=>this.saveKonfigElementHandler(e)}>Save</button></li>
and then use querySelector to get it:
saveKonfigElementHandler(e) {
const { value } = document.querySelector(e.target.getAttribute("data-input"));
// Use `value` ...
}
but the you're having to keep selectors unique, etc.
Which you choose, controlled or uncontrolled, is ultimately up to you.
I'm not sure about your question. Do you want something like this ?
<button data-input="#id-input" onClick={this.saveKonfigElementHandler(value)}>Save</button></li>
saveKonfigElementHandler = (value) => (event) => {}

react multiple binding but only for one side

I have 2 inputs the first one has setState like
<input onChange={e => this.setState({ price: e.target.value })} />
and the second one I do
<input value={this.state.price} />
This will do binding. Updating the first one will update the second one. But I want to modify the second one without dependent on the first one. I did find one solution; to use defaultValue instead of value. But the problem is input one no longer updates input two on onKeyPress events.

React - Show different value in input box based on the state

Problem Question - I have a form. The form has a state of editable and non-editable, which makes the input box to edit. Now this particular input box has to show different value depending upon what state it is in. i.e if it is not in editable state it has to show '27 November 2016' and if editable state it has to show '27/11/2016'.
The problem is when i try to edit this input box, therefore remove the pre defined value '27/11/2016' it does not work. I think it is not possible to bind function with value.
What I tried -
function showDate() {
if(!this.props.isEdit){
return longDate();
}
return shortDate();
}
<input
id='test'
value={this.showDate()}
onChange={this.props.onInputChange}
readOnly={!this.props.isEdit}
/>
Can someone please suggest on this?
Update: I have a Component which has function onInputChange and all i want to show different content inside input box when the form is in edit mode.
you should use state instead of props for input change, something like below
function onInputChange() {
if(!this.props.isEdit){
this.setState({
date: longDate()
});
return;
}
this.setState({
date: shorDate()
});
}
<input
id='test'
value={this.state.date}
onChange={onInputChange}
readOnly={!this.props.isEdit}
/>

Categories