I have a form that I built using material UI that I would like to have their default values from an API. The main idea is an Edit screen where the user can edit the details and then send them back. However, I cannot seem to get it working at all.
First, I get the data using an axios.get request:
let { id } = useParams();
const [unit, setUnit] = useState("");
useEffect(() => {
axios.get(`http://localhost:3001/units/${id}`).then((response) => {
setUnit(response.data);
});
}, []);
Then I assign the value I want to a state:
const [name, setName] = useState(unit.name);
Finally, I try to set it as the value (since I read that defaultValue cannot be controlled):
<TextField
required
label="Unit Name"
value={name}
onChange={(event) => {setName(event.target.value)}}
fullWidth
variant="outlined"
/>
However, the field does not contain any value. I tried assigning unit.name to a normal const and assign it to the textfield value and it worked but I could not edit it.
In your case, you could change the value to the default value and then you could edit it.
<TextField
required
label="Unit Name"
defaultValue={name}
onChange={(event) => {setName(event.target.value)}}
fullWidth
variant="outlined"
/>
Working solution is setting the name after receiving the Axios request with the data:
setName(response.data.name)
Then set it as the value and using the onChange normally
<TextField
required
label="Unit Name"
value={name}
onChange={(event) => {setName(event.target.value)}}
fullWidth
variant="outlined"
/>
I am running into a similar issue, I am first getting the data on the main component and the passing the entire value to the edit modal, it works fine as long as there is a value, but if any of the value's are null it will essentially crash
for Editing, I just have a new form state in the modal component, and on Change pass that to the form state.
Related
I have react-select dropdown menu and hidden input which I pass to form when submiting...
using useState hook I created variable which tracks changes to react-select dropdown menu.
Hidden input has this variable as value also. I thought this would be enough.
But when I submit the form, console. log shows me that value of input is empty despite that variable that was selected from dropdown menu is actually updated.
I mean variable that I have chosen console logs some value, but hidden input thinks that it is still empty.
Does it means I have to rerender manually page each time I change that variable so input gets it's new value using useEffect ? Which is bad solution for me, I don't like it, thought it would be done automatically.
Or instead of useState I must create and use variable via Redux ? Which I also don't like, use redux for such small thing fills overcomplicated.
Isn't there any nice elegant solution ? :)
import { useForm } from 'react-hook-form';
const [someVar,setSomeVar]=useState('');
const {
register,
handleSubmit,
formState: { errors },
} = useForm({ mode: 'onBlur' });
const handleFormSubmit = (data) => {
console.error('success');
};
const handleErrors = (errors) => {
console.error(errors);
console.log(document.getElementsByName('hiddenInput')[0].value);
};
const options = {
hiddenInput: {
required: t('hiddenInput is required'),
},
};
.......
<form onSubmit={handleSubmit(handleFormSubmit, handleErrors)}>
<Select
options='...some options list'
onChange={(value) => setSomeVar(value)}
/>
<input
name='hiddenInput'
value={someVar}
{...register('hiddenInput', options.hiddenInput)}
/>
<button>submit</button>
</form>
UPDATED
Its because getElementsByName returns an array of elements.
You probably want
document.getElementsByName('hiddenInput')[0].value
I should add that really you should use a ref attached to the input and not access it via the base DOM API.
const hiddenRef = useRef(null)
// ...
cosnt handleSubmit =(e)=>{
console.log(hiddenRef.current.value);
}
// ...
<input
name='hiddenInput'
value={someVar}
ref={hiddenRef}
/>
However as you are using react-hook-form you need to be interacting with its state store so the library knows the value.
const {
register,
handleSubmit,
formState: { errors },
setValue
} = useForm({ mode: 'onBlur' });
// ...
<form onSubmit={handleSubmit(handleFormSubmit, handleErrors)}>
<Select
options='...some options list'
onChange={(value) => setValue('hiddenInput', value)}
/>
<input
name='hiddenInput'
{...register('hiddenInput', options.hiddenInput)}
/>
<button>submit</button>
</form>
You can remove const [someVar,setSomeVar]=useState('');
However, this hidden input is not really necessary as you mention in comments. You just need to bind the dropdown to react hook form.
// controller is imported from react hook form
<form onSubmit={handleSubmit(handleFormSubmit, handleErrors)}>
<Controller
control={control} // THIS IS FROM useForm return
name="yourDropdown"
rules={{required: true}}
render={({
field: { onChange, value, name, ref }
}) => (
<Select
options={options}
inputRef={ref}
value={options.find(c => c.value === value)}
onChange={val => onChange(val.value)}
/>
)}
/>
<button>submit</button>
</form>
This is the code I have, but it's not displaying properly
<TextField
size="small"
className="typing-container"
defaultValue={thing.thingLastName}
label="Last Name"
onChange={(event) => setFirst(event.target.value)}
required
/>
when I change defaultValue to value, it displays but then you can't edit the field at all. This all displays properly when used earlier inside a h5 tag
You probably want to store the value in local state. Something like:
const MyComp => {
const [value, setValue] = useState(defaultValue)
return (
<TextField
...
onChange={(event) => setValue(event.target.value)}
value={value}
/>
)
}
then whenever your onChange event fires, it updates the value and passes it into the TextField. We don't need to use the defaultValue prop anymore because the useState hook takes a default value and sets that as the initial value for value
Try pass a state to value property, set the state to the default value that you want, later change the value using the onChange property.
function Comp () {
const {value, setValue} = useState('Default Value')
return (
<TextField
value={value}
onChange={(event) => setValue(event.target.value)}
required
/>
)
}
I have a in a form using react final form. I'm trying to pass the value of the current input to a function thats used when the field value changes. However when I type, it's taking no input.
<Field name="myField">
{({ input, meta }) => (
<div>
<TextField
type="text"
name={input.name}
value={input.value}
onChange={() =>
handleChange(input.value)
}
label="Title"
/>
</div>
)}
</Field>
I have a function handleChange above the render method. All I want to do is console the current value, and use a setState hook to update a state variable.
function handleChange(item: string) {
setTitle(item);
console.log(item);
}
What am I doing wrong?
I would personally use a useEffect to achieve this, but the issue is that once you add your own useEffect onto it, then it overrides the default action which saves the form value to the form itself.
So first you still have to do the default onChange. And you want to take the value from the input field using e.target.value.
In your example, you are passing the value of the input field into your handeChange, but becuase you arent saving the value back into the input and the form, its always going to be empty.
<Field name="myField">
{({input}) => (
<div>
<TextField
name={input.name}
value={input.value}
onChange={(e, val) => {
console.log(e.target.value);
handleChange(e.target.value)
input.onChange(e.target.value);
}}
/>
</div>
)}
</Field>
I am trying to create a basic form using Grommet following the examples at https://v2.grommet.io/form. My specific form looks like this:
import React from 'react';
import { Box, Form, FormField, TextInput, Button } from 'grommet';
const defaultValue = {};
const LoginForm = () => {
const [value, setValue] = React.useState(defaultValue);
function handleSubmit(e) {
e.preventDefault();
const { email, password } = e.value;
console.log('pretending to log in:', email, password);
// doLogin(email, password)
}
return (
<Form
value={value}
onChange={nextValue => {
setValue(nextValue);
}}
onReset={() => setValue(defaultValue)}
onSubmit={handleSubmit}
>
<FormField label="email" name="email" required>
<TextInput name="email" />
</FormField>
<FormField label="password" name="password" required>
<TextInput name="password" />
</FormField>
<Box direction="row" justify="between" margin={{ top: 'medium' }}>
<Button type="reset" label="Reset" />
<Button type="submit" label="Login" primary />
</Box>
</Form>
);
};
As soon as I start typing into either field, I get the following:
Warning: A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: ...
Note that I get the exact same error if I replace my form code with a cut/paste from the example in the link above.
I have a fairly reasonable understanding of what the error means, but I have no idea how to fix it in this case. Is Grommet's implementation of controlled form components broken, or am I missing something elsewhere in my configuration or packages that might be causing this?
The React.js controlled standards are not allowing objects to be undefined.
So the problem starts with how you've defined your defaultValue = {};, since it is an empty object, there is no initial value to the FormField children and that causes them to be undefined and hence the error.
So if you'll change the preset value to be more accommodating to your fields, such as defaultValue = { password: '' }; it will fix your error.
For more reading about React controlled and uncontrolled inputs read this A component is changing an uncontrolled input of type text to be controlled error in ReactJS
I am writing a front-end app in Typescript and React and am using MUI. I have the following code for a form:
<TextField
label="Password"
value={this.state.password}
placeholder="Choose a password"
type="password"
onChange={(event: any) => this.setState({
password: event.target.value
})}
onBlur={console.log('here')}
error={this.state.passwordError}
/>
With this code, every time I click a key, onBlur gets fired. Isn't it only supposed to fire when I leave the form?
Would be helpful to see the onblur function. It doesn't look like you want to pass anything to it, so simply changing the line onBlur={this.onblur()} to onBlur={this.onblur} should do the trick.
However, if your function looks like this
onblur() {
...
}
then you should bind the context to it ('this'). Instead, I'd suggest going for
onblur = event => {
...
}
which will have the context already binded.