I'm pre-populating an input field, using the data from an API. It's showing up just fine but I can't seem to edit it as it's not possible to edit the "value" field of an input field.
Here's what I want to do:
I want to pre-populate the input fields, edit the data inside them and then push the updated data back to the API.
For example, for the input field with the name Street Address, it's pre-populating the value from the API. In this case "Manhattan". I want to then change that value inside the input field to "New York" and send it back to the API, so that inside the JSON file it will update this specific value.
The left input field from the image is not pre-populating data from the API. Thus, it's empty.
Here's what I've got now.
function WarehousesDetailsEdit() {
const { id } = useParams();
const [warehouseData, setWarehouseData] = useState([]);
const [userInput, setUserInput] = useState([]);
const handleChange = (e) => {
setUserInput((recentInput) => ({ ...recentInput, [e.target.name]: e.target.value }));
};
useEffect(() => {
axios
.get(`http://localhost:8080/warehouses/${id}`)
.then((resp) => {
setWarehouseData(resp.data.warehouseDetails[0]);
})
.catch((err) => {
console.log(err, "Error!");
});
}, [id]);
return (
<>
// here, I'm able to update the input field as it's not coming from the API
<input
name="Warehouse Name"
value={userInput.WarehouseName}
onChange={handleChange}
/>
// here, the field was pre-populated using the API. Meaning, I can't update it.
<input
name="Street Address"
value={warehouseData.name}
onChange={handleChange}
/>
</>
)
I've not included the axios.put() in the code as it doesn't seem relevant right now as I just want to be able to update the pre-populated input field for now.
You're explicitly setting the value:
value={warehouseData.name}
And then nothing ever changes what's in warehouseData. Contrast that with the other <input> where the onChange event changes the value.
You can approach this in a couple of ways. Probably the simplest is to not have a warehouseData state at all. Just update the userInput state with the "pre-populated value". For example:
.then((resp) => {
setUserInput((recentInput) => ({ ...recentInput, name: resp.data.warehouseDetails[0].name }));
})
Then both <input> elements can just use userInput:
<input
name="Street Address"
value={userInput.name}
onChange={handleChange}
/>
Alternatively, if you want to keep both objects in their own separate state for some other reason, then you'd need to update that state. You can create a separate change handler for that:
const handleWarehouseDataChange = (e) => {
setWarehouseData((recentData) => ({ ...recentData, [e.target.name]: e.target.value }));
};
And use that in your <input>:
<input
name="Street Address"
value={warehouseData.name}
onChange={handleWarehouseDataChange}
/>
Related
I have a two step component, in which the user selects from a dropdown. An input field then appears and the user is prompted to enter into this area, for example dropdown selected item is 'knife', and the input may be 'butter', I want to create an array which has keyed data in this format.
const initialState = [
{
"selectedExperience": "whatever you selected in dropdown",
"experience": "5 years"
}
]
I have the data currently stored on useState which is then sent to the final state below:
const [finalselected, setfinalSelected] = useState([]);
However, when I use the current function it appears it's spreading across 0,1,2,3 etc and is incorrect. Please see screenshot: https://gyazo.com/11d95b11b6077de9b6907f3da755c6b9
These are my functions, what is incorrect?
Dropdown:
<Dropdown_Item
key={option}
value={option}
onClick={(e) => {
setselectedExperience(option);
setisActive(!isActive);
// onPerksClick(option);
}}
>
Input field:
<UserInput type="text" name="experience" placeholder="Enter years required"
onChange={handleInputField}
/>
const handleInputField = (e) => {
//include all in the state earlier with spread
//update only position, which is input
e.preventDefault()
setinputfield(prev=>({...prev, [e.target.name]:e.target.value}))
console.log(inputfield)
}
Final onSubmit function, where I would like to add the two above states into one called finalSelection with the ideal array identified earlier!
const onSubmitFinalSelection = (val) => {
if (!finalselected.includes(selectedExperience)) {
setfinalSelected((prev) => [...prev, selectedExperience, inputfield]);
}
console.log('final selection array is', finalselected)
console.log('executed onclick')
};
I have a form that gets it's input fields dynamically, it can have hundreds of fields so i can't create a state individually, I was planning on doing something like using an object using the unique key of a form field but need some help.
Suppose the form has fields like this.
<form>
{inputFields.map((i) => {
<input type={i.type} />
})}
</form>
Now i would need a state like the one below
inputState = {
"INPUT_FIELD_NAME1": "INPUT FIELD VALUE 1",
"INPUT_FIELD_NAME2": "INPUT FIELD VALUE 2",
"INPUT_FIELD_NAME3": "INPUT FIELD VALUE 3",
}
I need help with this, how do i set values in such a manner in my input onChange and how do i access the values from the state and use them for the matching input field?
As per my understanding and knowledge, you have to update your dynamic structure like given as below
<form>
{inputFields.map((i) => (
<input
type={i.type}
name={`INPUT_FIELD_NAME${i.id}`}
onChange={handleChange}
/>
))}
</form>
Also have to update your react state on input change like
const [inputState, setinputState] = useState({});
const handleChange = (e) => {
const { name, value } = e.target;
setinputState({
...inputState,
[name]: value
});
};
I hope it will work for you! Thanks.
I would do something like this:
const [form, setForm] = useState({})
const onChange = (event) => {
const { id, value } = event.target
setForm((prev) => ({ ...prev, [id]: value }))
}
<form>
{inputFields.map((i) => {
<input key={i.id} onChange={onChange} id={i.id} type={i.type} />
})}
</form>
Id must be unique, also you can use "name" property instead of "id"
React Hook Forms detect that I change the value of text input when I type something (onChange). But can it also detect the change if I enter data to the input by value={value}?
const validator = register(name);
I need something like
onValueSet={(e) => {
validator.onChange(e);
}}
I mean if I just set data by value={value} I get an error that this input is required. I don't want this error, because data was set by value={value}.
Here is my input:
<StyledInput
name={name}
maxLength={100}
value={value}
onChange={(e) => {
validator.onChange(e);
}}
/>
and my validation schema:
const validationSchema = Yup.object().shape({
first_name: Yup.string()
.required("required"),
});
You have to use reset here and call it when you received your initial form data. I assume you're doing an api call and want to set the result to the form. You can do so with useEffect, watching when you're data has resolved and then reset the form with the actual values. This way you don't have to set the value via the value prop and let RHF manage the state of your inputs. You also don't need to set name prop, as RHF's register call returns this prop as well.
const Component = (props) => {
const { result } = useApiCall();
const { register, reset } = useForm();
useEffect(() => {
reset(result)
}, [result]);
return (
...
<StyledInput
{...register('first_name')}
maxLength={100}
/>
...
)
}
Here is a little CodeSandbox demonstrating your use case:
You can define an onfocus or onkeyup event and call the validation function there instead of onChange event.
<StyledInput
name={name}
maxLength={100}
value={value}
onfocus={(e) => {
validator.onChange(e);
}}
/>
Instead of triggering the validator when input changes, you can instead call your validator through the onBlur event. And I am not sure how you are using react-hook-form .. but the useForm hook has a config mode (onChange | onBlur | onSubmit | onTouched | all = 'onSubmit') on when to trigger the validation:
I have a list and edit button when user click edit button opening a new modal. I want to auto populate the selected username mail etc. Server side response is {this.test.name} i give him to input value to auto populate but when user click edit button ı can see the name but ı couldnt change the input how do ı do that ?
Code :
<div className = "form__group field">
<input type="input" className="form__field" placeholder="Name" name="name" id="name" value={this.test.name} />
<label htmlFor="name" className="form__label">Adı-Soyadı</label>
</div>
You cannot change that input value because you've set the value to this.test.name and did not defined an onChange handler. So what you should do is create a state for your input field and on componentDidMount, populate this state with data from server.
Then on your input field
this.state = {
val: ''
}
<input value={this.test.name} onChange={e => setState({val: e.target.value})}/>
Maybe there can be a syntax error, because I am used to work with hooks now, but that's pretty much the gist of it
Keep the name in the state:
this.state = {
name: '',
}
(setState when you have it, if you retrieve it only on mount)
Pass value={this.state.name} to the input.
Pass onChange={handleNameChange} to the input.
const handeNameChange = (e) => {
setState({ name: e.target.value });
}
If you are using hooks, you could do something like this:
import { useState } from "react"; // import useState
export default function App() {
const [name, setName] = useState(""); // useState hook
// handle change event
const handleChange = (e) => {
e.preventDefault(); // prevent the default action
setName(e.target.value); // set name to e.target.value (event)
};
// render
return (
<div>
<input value={name} type="text" onChange={handleChange}></input>
<p>{name}</p>
</div>
);
}
First, we import the useState() hook to be able to use it, then we use it to store the state for the name value, you can give it an initial value of an empty string (""). In the handleChange() function, we prevent the default action and set the state to e.target.value, this is the input value passed by the event (as (e)). Every time the input changes, the state will update and the page will re-render.
You could check out my sandbox here
The input doesn't change it's text. It comes pre-filled from the database. For example, if it comes with the text: example, if I press for example the s key, it console logs examples but in the DOM in is still example. Here is the handle code:
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
console.log(event.target.name);
console.log(event.target.value);
};
and the input field:
<input
type="text"
className="form-control"
name="note"
id=" note"
value={this.state.insurance.note}
onChange={this.handleChange}
/>
EDIT (fixed the render problem, but I don't get the data that I want when I submit the form)
Here is the code for my form:
handleSubmit = event => {
event.preventDefault();
var state = this.state;
axios
.put(`${API_URL}/` + state.id + `/update`, {
tip: state.tip,
date_exp: state.date_exp,
date_notif: state.date_notif,
note: state.note
})
.then(response => {
console.log(response.data);
// window.location = "/view";
})
.catch(error => {
console.log(error);
});
}
and my button is a simple submit button:
<button className="btn btn-success" type="submit">Save</button>
imjared's answer is correct: your problem is in the handleChange function, where you wrongly update the state.
That function should be something like the following one:
handleChange = event => {
const insurance = Object.assign({}, this.state.insurance);
insurance[event.target.name] = event.target.value;
this.setState({insurance});
};
In the first line of the function, you create a deep copy of the current object insurance saved in the state. Then, you update the copied object, and finally update the state.
You're changing this.state.note based on the name property of your input so it makes sense that this.state.insurance.note wouldn't see any updates.
If you try console.logging this.state above your <input>, I bet you'll see what you're after.