I have a form that should print the data in console but unfortunately I'm not able to.
I want to print data to the console when a form is submitted.
The form is not submitting don't know why. I have the code below.
I would be very grateful if you could decide.
import { Button, Grid, Paper, TextField } from "#mui/material";
import React from "react";
import { useForm } from "react-hook-form";
export default function Page2(props) {
const { handleSubmit } = useForm();
const handelInputChange = (e) => {
const { name, value } = e.target;
console.log(name, value);
};
const handleData = (data) => {
console.log("data");
};
return (
<>
<Paper
style={{ margin: "10px auto", textAlign: "center" }}
elevation={24} >
<h1 style={{ textAlign: "center" }}>Todo Application</h1>
<form onSubmit={handleSubmit(handleData)}>
<Grid
style={{ margin: "10px" }}
container
spacing={1}
direction="column" >
<Grid item xs={6}>
<TextField
name="title"
label="Title"
variant="standard"
onChange={handelInputChange} />
<TextField
name="desc"
label="Description"
variant="standard"
onChange={handelInputChange} />
<TextField
name="priority"
type="number"
label="Priority"
variant="standard"
onChange={handelInputChange} />
</Grid>
</Grid>
</form>
<button type="submit" variant="contained" color="primary">
Add
</button>
</Paper>
</>
);
}
You have wrong HTML structure. button[type=submit] should be inside <form> tag
In addition to Steve, You can use simply register function to do the work for you just supply register function in the inputRef of your MUI Form Component.
import { Button, Grid, Paper, TextField } from "#mui/material";
import React from "react";
import { useForm } from "react-hook-form";
export default function Page2(props) {
const { handleSubmit, register } = useForm();
const handelInputChange = (e) => {
const { name, value } = e.target;
console.log(name, value);
};
const handleData = (data) => {
console.log("data",data);
};
return (
<>
<Paper
style={{ margin: "10px auto", textAlign: "center" }}
elevation={24} >
<h1 style={{ textAlign: "center" }}>Todo Application</h1>
<form onSubmit={handleSubmit(handleData)}>
<Grid
style={{ margin: "10px" }}
container
spacing={1}
direction="column" >
<Grid item xs={6}>
<TextField
name="title"
label="Title"
variant="standard"
inputRef={register}
onChange={handelInputChange} />
<TextField
name="desc"
label="Description"
variant="standard"
inputRef={register}
onChange={handelInputChange} />
<TextField
name="priority"
type="number"
label="Priority"
variant="standard"
inputRef={register}
onChange={handelInputChange} />
</Grid>
</Grid>
<button type="submit" variant="contained" color="primary">
Add
</button>
</form>
</Paper>
</>
);
}
You have quite a bit of things to do in order to get this form to console.log. First, as the other poster mentioned, the submit button needs to be within the form (and you probably want to uppercase that B in "<Button" so that you're using the MUI component.
<form onSubmit={handleSubmit(handleData)}>
<Grid
style={{ margin: "10px" }}
container
spacing={1}
direction="column"
>
<Grid item xs={6}>
<TextField
name="title"
label="Title"
variant="standard"
onChange={handelInputChange}
/>
...
</Grid>
</Grid>
// Moved and renamed here
<Button type="submit" variant="contained" color="primary">
Add
</Button>
</form>
That solves your submit problem, but then you will notice that the console.log("data") will only ever contain an empty object {} -- this is because react-form-hooks needs to be given a FormProvider and made aware of the form elements in the form that it should control. To do this you need to register the component. I have added working code example on one way to complete this task.
In this example, I created a generic FormFieldController wrapper that you can use to pass in whatever just about form fields you need. (I would not use this in production code, without cleanup, as it is only meant as an example):
const FormFieldController = ({
component: Component = TextField,
name = "",
defaultValue = "",
label = "",
validation = {},
required = false,
valueProp = "value",
callbackProp = "onChange",
onChange,
...rest
}) => {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
defaultValue={defaultValue}
rules={validation}
render={({
field: { onChange: internalOnChange, value, ref },
fieldState: { error }
}) => {
const pipes = {
[valueProp]: value,
[callbackProp]: function () {
internalOnChange.apply(this, arguments);
// Middleman callback to allow for onChange back to the caller, if needed
if (onChange) {
onChange.apply(this, arguments);
}
}
};
return (
<>
<Component
id={name}
inputRef={ref}
caption={error ? error?.message : ""}
label={label}
{...pipes}
{...rest}
/>
</>
);
}}
/>
);
};
Working CodeSandbox Example
Related
I'm trying to show the data, I fetched from Api in select menu. but there seems to be a issue. I'm getting the data, but it's not showing in the select menu. it just shows empty. but I can get the mapped data in console. it just not showing in the select component.
help me figure out. thanks in advance :)
here's my code
export function TransferRBTCard(props) {
const [TransferData, setTransferData] = useState([])
const [ContactValue, setContactValue] = useState('')
const handleChange = (event) => {
setContactValue(event.target.value);
};
const TokenData = () => {
axios.get('http://localhost:8006/api/v2/get/list').then(function (res) {
try {
var result = res.data.data;
console.log(result)
setTransferData(result)
}
catch (error) {
console.log(error)
}
})
}
useEffect(() => {
TokenData()
}, [])]
const handleSubmit = (evnt,) => {
evnt.preventDefault();
axios.post('http://localhost:8006/api/v2/add/transfer')
.then(response => {
if (response.data.success === true) {
alert(response.data.message)
}
})
.catch(error => {
console.log(error.message)
});
}
return (
<Card {...props}>
<CardContent>
<Stack direction="row" alignItems="center" gap={1}>
<ShareOutlinedIcon sx={{ color: "text.secondary" }} />
<Typography sx={{ fontSize: 16, fontWeight: 'bold' }} color="text.secondary" gutterBottom>
Transfer RBT
</Typography>
</Stack>
<Grid>
<FormControl size="small" fullWidth >
<Stack flexDirection='column' gap={1.5} mt={1}>
<InputLabel id="Contact Select" sx={{ mt: 1 }}>Select Contact</InputLabel>
<Select
labelId="Contact Select"
id="demo-simple-select"
value={ContactValue}
label='Select Contact'
onChange={handleChange}
>
{TransferData.map((data) => {
<MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
})}
</Select>
<TextField
id="filled-hidden-label-small"
label="Receiver" variant="outlined" size="small"
onChange={handleChange}
value={TransferData}
name="Receiver"
inputProps={
{ readOnly: true, }}
className="form-control"
/>
<TextField
id="filled-hidden-label-small" type='number'
label="Amount" variant="outlined" size="small"
onChange={handleChange}
name="Amount"
className="form-control"
/>
<TextField
id="filled-hidden-label-small"
label="Comments" variant="outlined"
multiline
rows={2}
onChange={handleChange}
name="Comments"
className="form-control"
/>
<Button
variant="contained"
type="submit"
onClick={handleSubmit}
sx={{ alignSelf: 'center', backgroundColor: '#000073' }} >Submit</Button>
</Stack>
</FormControl>
</Grid>
</CardContent>
</Card>
);
}
You are not returning from the map function (more correctly, you return undefined by not stating a return).
Change this:
{TransferData.map((data) => {
<MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
})}
to this:
{TransferData.map((data) => (
<MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
))}
Note that it is the same as writing:
{TransferData.map((data) => {
return <MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
})}
props.children is not working in my parent component, BoxCard. When I reference the child component directly instead of props.children, it works. Here's the code that's not working:
// AddUserForm.js
function AddUserForm(props) {
function handleSubmit(event) {
event.preventDefault();
}
return (
<BoxCard>
<Box component="form" onSubmit={handleSubmit}>
<TextField required id="name" label="Name" variant="filled" />
<TextField required type="number" id="age" label="Age" variant="filled" InputLabelProps={{ shrink: true }} InputProps={{inputProps: { min: 0, step: 1 }}}/>
<Button type="submit" variant="contained" startIcon={<FontAwesomeIcon icon={solid('circle-plus')}/>}>Add User</Button>
</Box>
</BoxCard>
)
}
export default AddUserForm;
// BoxCard.js
function BoxCard(props) {
return (
<Box sx={{ minWidth: 275 }}>
<Card variant="outlined">
<CardContent>
{props.children}
</CardContent>
</Card>
</Box>
)
}
export default BoxCard;
I have a Material-UI Select inside a nested useFieldArray. Every time I'll add the Material-UI Select and submit it to the form, whatever values that were entered in the form will not be saved and do not log in to the console. Also, I keep on having this warning when I do not have a ref anymore.
Link to codesandbox where codes are complete here: https://codesandbox.io/s/react-hook-form-usefieldarray-nested-arrays-forked-vjwbp?file=/src/nestedFieldArray.js:0-1722
Warning: Invalid value for prop refer on tag. Either remove it
from the element, or pass a string or number value to keep it in the
DOM.
Material-UI select
import { InputLabel, MenuItem, FormControl, Select } from "#mui/material";
const Size = ({ name, refer, defaultValue }) => {
return (
<FormControl fullWidth variant="filled">
<InputLabel id="Size Label">Size</InputLabel>
<Select
labelId="Size"
id="size"
name={name}
label="Product"
refer={refer}
defaultValue={defaultValue}
>
<MenuItem value="S">Small</MenuItem>
<MenuItem value="M">Medium</MenuItem>
<MenuItem value="L">Large</MenuItem>
</Select>
</FormControl>
);
};
export default Size;
I'm using the Size here:
import React from "react";
import { useFieldArray } from "react-hook-form";
import Size from "./Drop_drowns/Size";
import { TextField } from "#mui/material";
export default ({ nestIndex, control, register }) => {
const { fields, remove, append } = useFieldArray({
control,
name: `test[${nestIndex}].nestedArray`
});
return (
<div>
{fields.map((item, k) => {
return (
<div key={item.id} style={{ marginLeft: 20 }}>
<label>Colors:</label>
<Size
name={`test[${nestIndex}].nestedArray[${k}].field1`}
refer={register({ required: true })}
defaultValue={item.field1}
style={{ marginRight: "25px" }}
/>
{/* <input
name={`test[${nestIndex}].nestedArray[${k}].field1`}
ref={register({ required: true })}
defaultValue={item.field1}
style={{ marginRight: "25px" }}
/> */}
<TextField
name={`test[${nestIndex}].nestedArray[${k}].field2`}
refer={register()}
defaultValue={item.field2}
/>
<TextField
name={`test[${nestIndex}].nestedArray[${k}].field3`}
refer={register()}
defaultValue={item.field3}
/>
<button type="button" onClick={() => remove(k)}>
Delete Colors
</button>
</div>
);
})}
<button
type="button"
onClick={() =>
append({
field1: "field1",
field2: "field2"
})
}
>
Add Colors
</button>
<hr />
</div>
);
};
So i put together this Dynamic Form Below (Hotel Rooms) and inside it you can also create dynamic forms (Room Beds). It works, i can add rooms & Beds and the object array is returned in the console.log (onSubmit).
codesandbox: https://codesandbox.io/s/charming-hermann-nzpbu?file=/src/App.js
Issue:
If you add room1 and room2 and then delete room1, the array stays of length 2 and now it has "beds undefined" and it keeps growing when you add beds to other rooms! Help me solve this:
Object returned when you press next (in console). As you can see the array is not subtracting but it is also leaving the beds undefined when i delete a room:
listingDescription: "ss"
listingName: "aa"
pricePerMonth: 1
rooms: Array(2)
0: {roomname: "room2", beds: Array(1)}
1: {beds: undefined}
The Main Form:
import React from 'react';
import { useStateMachine } from 'little-state-machine';
import { useForm } from 'react-hook-form';
import { Row, Col, Input, InputNumber, Button, Form, Space } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '#ant-design/icons';
import FormControl from 'components/UI/FormControl/FormControl';
import AddListingAction from './AddListingAction';
import { FormHeader, Title, FormContent, FormAction } from './AddListing.style';
import BedForm from "./BedForm";
const BasicInformation = ({ setStep }) => {
const { action, state } = useStateMachine(AddListingAction);
const { control, register, errors, setValue, handleSubmit } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<Form onFinish={(e) => onSubmit(e)}>
<FormContent>
<FormHeader>
<Title>Step 1: Start with the basics</Title>
</FormHeader>
<Row gutter={30}>
<Col sm={12}>
<FormControl
label='Listing Name'
htmlFor='listingName'
error={errors.listingName && <span>This field is required!</span>}
>
<Form.Item
id='listingName'
name='listingName'
defaultValue={state.data.listingName}
control={control}
placeholder='Write a name for your listing here'
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
</FormControl>
</Col>
<Col sm={12}>
<FormControl
label='Price Per Night (USD)'
htmlFor='pricePerMonth'
>
<Form.Item
name='pricePerMonth'
id='pricePerMonth'
defaultValue={state.data.pricePerMonth}
control={control}
placeholder='00.00'
rules={[
{
required: true,
pattern: /^[0-9]*$/,
},
]}
>
<InputNumber min={0} />
</Form.Item>
</FormControl>
</Col>
</Row>
<FormControl
label='Listing Description'
htmlFor='listingDescription'
error={
errors.listingDescription && <span>This field is required!</span>
}
>
<Form.Item
id='listingDescription'
name='listingDescription'
defaultValue={state.data.listingDescription}
control={control}
placeholder='Tell people about your listing, rooms, location & amenities'
rules={[
{
required: true,
},
]}
>
<Input.TextArea rows={5} />
</Form.Item>
</FormControl>
<FormControl
label='How many rooms does your listing have?'
error={errors.guest && <span>This field is required!</span>}
>
{/* This is the Dynamic room Adder */}
<Form.List name='rooms'>
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field) => (
<Space
key={field.key}
style={{ display: 'flex', marginBottom: 8 }}
align='start'
>
<Form.Item
{...field}
name={[field.name, 'roomname']}
fieldKey={[field.fieldKey, 'roomname']}
rules={[
{ required: true, message: 'Missing room name' },
]}
>
<Input placeholder='Room Name' />
</Form.Item>
{/* This is the Dynamic bed Adder */}
<Form.Item>
<BedForm fieldKey={field.key} />
</Form.Item>
<MinusCircleOutlined
onClick={() => {
remove(field.name);
console.log(field)
}}
/>
</Space>
))}
<Button
type='dashed'
onClick={() => {
add();
}}
block
>
<PlusOutlined /> Add room
</Button>
</div>
);
}}
</Form.List>
</FormControl>
</FormContent>
<FormAction>
<div className='inner-wrapper'>
<Button type='primary' htmlType='submit'>
Next
</Button>
</div>
</FormAction>
</Form>
);
};
export default BasicInformation;
The Child Form (BedForm)
import React from 'react';
import { Form, Input, Button, Space, Select } from 'antd';
import { PlusOutlined, MinusCircleOutlined } from '#ant-design/icons';
const { Option } = Select;
//#ATT:this was created to make nested dynamic elements! This is hard!
const BedForm = (props) => {
return (
<>
<Form.List name={[props.fieldKey, 'beds']}>
{(beds, { add, remove }) => {
return (
<div>
{beds.map((bed, index2) => (
<Space
key={bed.key}
style={{ display: 'flex', marginBottom: 8 }}
align='start'
>
<Form.Item
// name={"aar"}
{...bed}
name={[bed.name, 'bed']}
fieldKey={[bed.fieldKey, 'bed']}
key={index2}
// noStyle
rules={[
{
required: true, message: 'Beds Missing'
},
]}
>
<Select placeholder="Please select a Bed Type">
<Option value='double'>Double(2 person)</Option>
<Option value='single'>Single (1 person)</Option>
<Option value='king'>King Size (2 person)</Option>
<Option value='queen'>Queen Size (2 person)</Option>
<Option value='Bunk'>Bunk Bed (1 person)</Option>
<Option value='sofa'>Sofa Bed (1 person)</Option>
</Select>
</Form.Item>
{/* <MinusCircleOutlined
onClick={() => {
remove(bed.name);
}}
/> */}
</Space>
))}
<Form.Item>
<Button
type='dashed'
onClick={() => {
add();
}}
>
<PlusOutlined /> Add Bed
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</>
);
};
export default BedForm;
Pass field.name instead of field.key or fieldKey on App.js
https://codesandbox.io/s/trusting-wind-elsdz?file=/src/App.js
I have a search bar component that should take the value of the input, however I am using useState for my getters and setters and i am a bit confused as it is reported an error of
Below is my component, can you spot the erorr?
const SuppliersNavBar = (props) => {
const { classes } = props;
const [search, setSearch] = useState();
const updateSearch = (event) => {
setSearch({ search: event.target.value });
console.log(event);
};
return (
<Fragment><Fab className={classes.addCircle} style={{ float: 'right',
marginRight: 10, marginBottom: 10, backgroundColor: '#3B70BC', color:
'white' }} onClick={() => { this.props.history.push('/'); }}
id="addCircle" ><Add /></Fab>
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<Grid container direction="row"
justify="flex-start"
alignItems="center">
<Grid item xs={12} sm={6} md={3}>
<div className={classes.grow} />
<div className={classes.search} aria-label="search bar">
<div className={classes.searchIcon}>
<Search id="searchIcon" />
</div>
<InputBase
aria-label="search bar"
value={search}
onChange={updateSearch.bind(this)}
placeholder="Search"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
/>
</div>
</Grid>
</Grid>
</Toolbar>
</AppBar>
</div>
</Fragment>
);
};
Events in React are handled through object pooling meaning that events aren't readable through the console. You can call event.persist() and you will be able to see it. Please look at this page for further information. https://reactjs.org/docs/events.html