Cannot edit in input react - reactjs

I am making an update form for user but I can't type in input tag when I added handleChange
Here is my code base:
const handleChange = (event) => {
const { name, value } = event.target;
// Update state
updatePlayersData((prevState) => ({
...prevState,
[name]: value,
}));
};
<input
value={title}
onChange={handleChange}
placeholder={title}
pattern="^[a-zA-Z0-9 ]+"
minLength="1"
maxLength="20"
/>

Because you're setting your inputs value to title variable everytime and not updating your title value.
<input
value={title} // you are not updating title value and using it on your value
onChange={handleChange}
placeholder={title}
pattern="^[a-zA-Z0-9 ]+"
minLength="1"
maxLength="20"
/>
as I understand it, you want to specify a default value. Try this one:
<input
defaultValue={title} // now it will change when you update input string
onChange={handleChange}
placeholder={title}
pattern="^[a-zA-Z0-9 ]+"
minLength="1"
maxLength="20"
/>

Kindly provide name="name_of_field" property to input element.
It will assign the input to the specified name_of_field and you can, later on, use it as input.name_of_field

In your code input doesn't have any name attribute. But in onChange method the state is being updated based on the name of the input. Hence, the changes are not getting reflected in the input.
So by adding name="title" attribute to the input and providing value={data.title} should work. Below I have added a snippet for the same
const { useState } = React;
const App = () => {
const [data, setData] = useState({});
const handleChange = (event) => {
const { name, value } = event.target;
setData((prevState) => ({
...prevState,
[name]: value,
}));
};
return <input
value={data.title}
onChange={handleChange}
placeholder={data.title}
pattern="^[a-zA-Z0-9 ]+"
minLength="1"
maxLength="20"
name="title"
/>
}
ReactDOM.render(<App />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Note: I have replaced updatePlayersData with setData for the example purpose. Also, in your code as per your requirement you can add any name for the input. But then make sure the same prop in the data to be passed as value to the input.

Related

Updating state value on at a time using useState

The below code is giving me a warning :
A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
when I am changing either password or username.
I am not able to figure out why I am getting this error.
Can someone tell me why exactly i am getting this error....
import React, { useState } from "react";
const Login = () => {
const [login, setLogin] = useState({ user: "", password: "" });
const handleChange = (e) => {
setLogin({ [e.target.name]: e.target.value });
};
return (
<div>
User Name{" "}
<input
onChange={handleChange}
type="text"
name="username"
value={login.user}
/>
Password{" "}
<input
onChange={handleChange}
type="password"
name="password"
value={login.password}
/>
<button>Login</button>
</div>
);
};
Unlike the class component's setState(), setting the state in functional components with useState() doesn't merge the update object with the previous state. Setting the state with useState() replace the previous one. That is why the state in useState() can be arrays, objects, or primitives.
In your case, when you the state - setLogin({ [e.target.name]: e.target.value });, you are replacing the entire state, and in effect remove the value of the other field. You should spread the previous value of the login state, and override just the value of the field that you are changing.
const { useState } = React;
const Login = () => {
const [login, setLogin] = useState({ user: "", password: "" });
const handleChange = (e) => {
setLogin(login => ({ ...login, [e.target.name]: e.target.value }));
};
return (
<div>
User Name{" "}
<input
onChange={handleChange}
type="text"
name="user" // this should be user and not username
value={login.user}
/>
Password{" "}
<input
onChange={handleChange}
type="password"
name="password"
value={login.password}
/>
<button>Login</button>
</div>
);
};
ReactDOM.render(
<Login />,
root
);
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>

userEvent.type not updating value of input in test

I am testing this component, which is simply changing its state depending on new input into the input field and setting the value of the input element to that state.
function Login () {
//Login Credentials
const [loginCredentials, setLoginCredentials] = useState({ name: '' })
const handleChange = ({target}) => {
setLoginCredentials(prev => ({ ...prev, [target.name]: target.value }));
}
return (
<div className="login-container">
<h1>Log In</h1>
<div className="login-label-input">
<label htmlFor="name">Account Name
<input
type="name"
id="name"
name="name"
placeholder="Enter Name"
onChange={handleChange}
value={loginCredentials.name}
aria-label="name"
/>
</label>
</div>
</div>
)
}
and for some reason this test does not show the value of input to be "testUser" in screen.debug() but only "t"....
test("log in with empty name input returns error message", () => {
render(<Login />)
const nameField = screen.getByLabelText(/account name/i);
userEvent.type(nameField, 'testUser');
screen.debug()
});
Shouldn't this work? Why doesn't it? excerpt from screen.debug():
<label
for="name"
>
Account Name
<input
aria-label="name"
id="name"
name="name"
placeholder="Enter Name"
type="name"
value="t"
/>
</label>
In the current version of #testing-library/user-event: ^14.2.0 and its corresponding official docs, there is an example where calling userEvent.type is awaited:
test('type into an input field', async () => {
render(<input defaultValue="Hello," />)
const input = screen.getByRole('textbox')
await userEvent.type(input, ' World!')
expect(input).toHaveValue('Hello, World!')
})
Callback in test() needs to be declared as async then, of course.
Link to this in the docs at time of writing: https://testing-library.com/docs/user-event/utility/#type
Nice to know maybe: Also works with uncontrolled components.
If you update jest to the latest version it will work. Currently, the latest jest is 26.6.3
This issue was discussed here: https://github.com/testing-library/user-event/issues/387
Your attribute "type" is invalid. The value "name" doesn't exist, try "text".

Set state for incremental numbers input

After months without reactjs I forgot how to solve this situation. I have a incremental input for numbers:
HTML:
<input
type="number"
value={stockQuantity}
defaultValue="1"
onChange={() => bookQuantity(stockQuantity)}
/>
React
const [stockQuantity, setStockQuantity] = useState(1);
const bookQuantity = (e) => {
setStockQuantity({ ...stockQuantity, [e.target.name]: e.target.value });
};
I just get errors I don't find the solution and I didn't find any previous work were I handle it.
Any idea?
You should define stockQuantity as an object initially:
const [stockQuantity, setStockQuantity] = useState({books: 1});
Then you can just setState in onChange event or create a separate function as you have already made.
You don't have to set the value prop
<input
type="number"
name="books"
defaultValue="1"
onChange={(e) => setStockQuantity({...stockQuantity, [e.target.name]: e.target.value})}
/>
You need to pass the event to your onChange handler and also add name to your input:
<input
type="number"
name="stockQuantity" // will be passed in e.target.name
value={stockQuantity}
defaultValue="1"
onChange={bookQuantity} // the same as onChange={(e) => bookQuantity(e)}
/>
I have found a little linear solution:
const [stockQuantity, setStockQuantity] = useState(1); // just numbers
const bookQuantity = (e) => {
setStockQuantity({ ...stockQuantity, [e.target.name]:
e.target.value });
};
HTML:
<input
type="number"
name="stock"
value={stockQuantity.books}
defaultValue="1"
onChange={bookQuantity}
// if you want you can use a placeholder
/>

Once the checkbox is checked, the text is not displaying in react hooks

Once the checkbox is checked, then I would like to display the input text field. By default the checkbox should not be checked and the token input field should be hidden.
Now I am getting below error and not working properly.
Warning: Failed prop type: You provided a checked prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultChecked. Otherwise, set either onChange or readOnly
const [checked, setChecked] = useState(false);
const [showToken, setShowToken] = useState({ show: false });
const handleClick = (e) => {
e.preventDefault();
setChecked(checked);
if(checked === true){
setShowToken({ show: true })
}
}
<label>
<input type="checkbox" onClick={handleClick} checked={checked}/>
{
showToken.show && (
<input className="inputRequest formContentElement" name="token" type="text" placeholder="token"/>
)
}
</label>
We can optimize code as,
Remove const [showToken, setShowToken] = useState({ show: false }); line
Use checked prop for display textbox.
Use setChecked hook for set checkbox checked changes.So we do not need handleClick method anymore.
You can do this simply as follows,
// Get a hook function
const {useState} = React;
const Example = () => {
const [checked, setChecked] = useState(false);
return (
<div>
<label>
<input type="checkbox" onChange={() => setChecked(!checked)} checked={checked}/>
{
checked ? (
<input className="inputRequest formContentElement" name="token" type="text" placeholder="token"/>
) : (<div></div>)
}
</label>
</div>
);
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

emptying the input after submiting a form

I'm trying to empty the input tag once I'm updating my state:
state = {
formName: '',
inputs: [],
tempInput: {
inputLabel: '',
inputType: '',
inputValue: ''
}
};
this is my form:
<div className="formG">
<form className="form-maker" onSubmit={this.handleSubmit}>
Label:
<input name="inputLabel" type="text" onChange={this.handleChange} />
Type:
<input name="inputType" type="text" onChange={this.handleChange} />
Value
<input name="inputValue" type="text" onChange={this.handleChange} />
Form Name
<input name="formName" type="text" onChange={this.formName} />
<button>Submit</button>
</form>
that's how I handle the change
handleChange = e => {
const { name, value } = e.target;
this.setState(currentState => ({
tempInput: { ...currentState.tempInput, [name]: value }
}));
};
and I tried to just empty the tempInput but it doesn't work, anybody knows why?
handleSubmit = e => {
e.preventDefault();
const inputs = [...this.state.inputs, this.state.tempInput];
const { tempInput } = this.state;
tempInput.inputLabel = '';
tempInput.inputType = '';
tempInput.inputValue = '';
this.setState({ inputs, tempInput });
};
Your form is an uncontrolled component, so they are not controlled by the state fields. That's why your approach didn't work. Instead you can do e.target.reset() which will clear the entire form. But if you want to reset some input, you can access them and set the .value to "" as I had shown below.
An uncontrolled component works like form elements do outside of React. When a user inputs data into a form field (an input box, dropdown, etc) the updated information is reflected without React needing to do anything. However, this also means that you can’t force the field to have a certain value. From Doc
So your handleSubmit method will look like:
handleSubmit = e => {
e.preventDefault();
const inputs = [...this.state.inputs, this.state.tempInput];
// ....
// The below will reset entire form.
// e.target.reset();
// If you want some of them to empty.
const { elements } = e.target
elements['inputLabel'].value = "";
elements['inputType'].value = "";
elements['inputValue'].value = "";
};
Check the doc of HTMLFormElement.elements
Your input tags are not displaying the value of your state.
1) pull the individual values out of tempInput
2) use the value stored in your state that is then updated by your handleChange.
3) In your handleSubmit function reset your individual values to and empty string.
your handleChange should look like:
handleChange = e => {
const { name, value } = e.target;
this.setState([name]: value);
};
your jsx should look like :
<form className="form-maker" onSubmit={this.handleSubmit}>
Label:
<input name="inputLabel" value={this.state.inputLabel} type="text" onChange={this.handleChange} />
Type:
<input name="inputType" value={this.state.inputType} type="text" onChange={this.handleChange} />
Value
<input name="inputValue" value={this.state.inputType} type="text" onChange={this.handleChange} />
Form Name
<input name="formName" value={this.state.formName} type="text" onChange={this.formName} />
<button>Submit</button>
</form>
You're mutating the original state. You can copy and then only set the state. Just changing the following will work fine for you.
Replace this:
const { tempInput } = this.state;
With this:
const { tempInput } = {...this.state}; // copy the state
Also, be sure to bind the state value in your input elements like this to make them controlled component:
<input name="inputLabel" type="text"
onChange={this.handleChange}
value={this.state.tempInput.inputLabel || ''} />
And your handler should be:
handleChange = e => {
const { value } = e.target;
this.setState({value});
// now, value will correspond to the controlled component
};
Also take care react suggest to use controlled component as far as possible:
In most cases, we recommend using controlled components to implement forms.

Resources