Ant Design - Modal with Datepicker (form) - reactjs

Reproduction link
codesandbox example
What is actually happening?
I enter the property name in the <Form.Item of the Datepicker and the application simply returns an error.
What is expected?
I want to work with dates in Modal, being able to retrieve a value from an object and send a Datepicker change to the form, as with text inputs
I intend to work with this object
{
name: "Wagner Fillio",
gender: "male",
birthday: "2022-02-20"
}
But I get the object below
import { useState } from "react";
import { Modal, Row, Col, Form, Input, DatePicker, Select, Button } from "antd";
import "./style.css";
export function Test() {
const [form] = Form.useForm();
const [isModalVisible, setIsModalVisible] = useState < boolean > false;
const initialValues = {
name: "Wagner Fillio",
gender: "male",
birthday: "2022-02-20",
};
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
form.resetFields();
setIsModalVisible(false);
};
const onFinish = async () => {
try {
const values = await form.validateFields();
console.log("Success:", values);
// Intended object
// {{name: 'Wagner Fillio', gender: 'male', birthday: '2022-02-20'}}
} catch (err) {
console.log(err);
}
};
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
width={300}
title="User"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
footer={[
<Button key="back" onClick={handleCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={onFinish}>
Submit
</Button>,
]}
>
<Form
form={form}
name="form-name"
layout="vertical"
initialValues={initialValues}
onFinish={onFinish}
>
<Form.Item name="name" label="Name">
<Input placeholder="Name" title="Name" />
</Form.Item>
<Form.Item name="gender" label="Gender">
<Select>
<Select.Option value="female">Female</Select.Option>
<Select.Option value="male">Male</Select.Option>
</Select>
</Form.Item>
<Form.Item label="Birthday">
<DatePicker />
</Form.Item>
</Form>
</Modal>
</>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Add name property for Form.Item and in OnFinish() function convert the date into required format
import { useState } from "react";
import { Modal, Row, Col, Form, Input, DatePicker, Select, Button } from "antd";
import "./styles.css";
export default function App() {
const [form] = Form.useForm();
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const initialValues = {
name: "Wagner Fillio",
gender: "male",
birthday: "2022-02-20"
};
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
form.resetFields();
setIsModalVisible(false);
};
const onFinish = async () => {
try {
const values = await form.validateFields();
values.birthday = values['birthday'].format('YYYY-MM-DD')
console.log("Success:", values);
// Intended object
// {{name: 'Wagner Fillio', gender: 'male', birthday: '2022-02-20'}}
} catch (err) {
console.log(err);
}
};
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
width={300}
title="User"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
footer={[
<Button key="back" onClick={handleCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={onFinish}>
Submit
</Button>
]}
>
<Form
form={form}
name="form-name"
layout="vertical"
initialValues={initialValues}
onFinish={onFinish}
>
<Form.Item name="name" label="Name">
<Input placeholder="Name" title="Name" />
</Form.Item>
<Form.Item name="gender" label="Gender">
<Select>
<Select.Option value="female">Female</Select.Option>
<Select.Option value="male">Male</Select.Option>
</Select>
</Form.Item>
<Form.Item name="birthday" label="Birthday">
<DatePicker />
</Form.Item>
</Form>
</Modal>
</>
);
}

Related

Why do i get error 400 on my graphQL mutation create user

I'm working with Reactjs and GraphQL integration. i got a problem when i'm doing mutation for new user.
Scenario :
Creating user using Modals bootstrap. when successful create new user, it shows alert or information success.
Code :
Here's my ModalCreate component code.
import React, { useState, useEffect } from 'react';
import { Button, Modal, Form } from "react-bootstrap";
const ModalCreate = (props) => {
// state for check input component
const [value, setValue] = useState({
username: props.username || '',
email: props.email || '',
fullname: props.full_name || '',
password: props.password || '',
phone: props.phone || '',
address: props.address || '',
groupid: props.group_id,
});
const onChange = event => {
setValue({
...value,
[event.target.name]: event.target.value
})
}
useEffect(() => {
if (props.show) {
document.body.classList.add("modal-open");
}
return () => {
if (document.body.classList.contains("modal-open")) {
document.body.classList.remove("modal-open");
}
};
}, [props.show]);
return (
<Modal show={props.show}>
<Modal.Header>
<Modal.Title> <span>FORMULIR AKUN PENGGUNA</span> </Modal.Title>
</Modal.Header>
<Modal.Body>
<Form onSubmit={e => {
e.preventDefault();
props.action({
variables: {
...value
}
})
}}>
<Form.Group className="mb-3">
<Form.Label>Role Akun</Form.Label>
<Form.Select aria-label="pilih user role" value={value.groupid} onChange={onChange}>
<option value="superadmin">Super Admin</option>
<option value="admin">Admin</option>
<option value="admin_rj ">Admin RJ</option>
</Form.Select>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Username</Form.Label>
<Form.Control name="username" value={value.username} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Nama Lengkap</Form.Label>
<Form.Control name="fullname" value={value.fullname} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Email</Form.Label>
<Form.Control type="email" name="email" value={value.email} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Password</Form.Label>
<Form.Control type="password" name="password" value={value.password} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Phone</Form.Label>
<Form.Control type="text" name="phone" value={value.phone} onChange={onChange}/>
</Form.Group>
<Button variant="secondary" type='submit'>
Simpan
</Button>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={props.onClose}>
Keluar
</Button>
</Modal.Footer>
</Modal>
);
};
export default ModalCreate;
and action/performing mutation in page call index.js :
import React, { useState } from 'react';
import { useQuery, useMutation } from '#apollo/client';
import { Container, Card, Button, InputGroup, FormControl, Form, Spinner } from 'react-bootstrap';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faSearch } from '#fortawesome/fontawesome-free-solid';
import CardInfo from '../../../component/PengaturanPengguna/CardInfo';
import TableUserInfo from '../../../component/PengaturanPengguna/Table';
import { Loading } from '../../../component/Common';
import ModalCreate from '../../../component/PengaturanPengguna/Modals/ModalCreate';
import { GET_ALL_USERS, GET_USER_BY_ID } from '../../../gql/query';
import { REGISTER_USER } from '../../../gql/mutation';
const SearchInput = () => {
return (
<InputGroup className="mb-3">
<InputGroup.Text>
<FontAwesomeIcon icon={faSearch} />
</InputGroup.Text>
<FormControl
type="text"
placeholder="Search..."
/>
</InputGroup>
)
}
const PengaturanPengguna = (props) => {
// refetch and query data
const { data: usersdata, loading: usersloading, error: userserror } = useQuery(GET_ALL_USERS);
const { refetch, loading } = useQuery(GET_ALL_USERS);
// show modals
const [showModal, setShowModal] = useState(false);
// mutation new register user
const [registerUser, { loading: registerloading, error: registererror }] = useMutation(REGISTER_USER, {
refetchQueries: [{ query: GET_USER_BY_ID }, { query: GET_ALL_USERS }],
onCompleted: data => {
console.log(data)
},
onError: err => {
console.error(err);
}
}) ;
const handleRefreshClick = () => {
refetch();
}
const handleShowModal = () => setShowModal(true);
const handleCloseModal = () => setShowModal(false);
if (usersloading || registerloading) return <Loading/>
if (userserror || registererror) return <p>Error!</p>
return (
<Container>
<CardInfo/>
<Card>
<Card.Title>
<span className='base-md text-regular mt-2 std-txt-primary-200'>Data Pengguna Dashboard</span>
</Card.Title>
<Card.Body>
<div className='d-flex justify-content-between'>
<Form inline>
<SearchInput/>
<Button variant='secondary' onClick={handleRefreshClick} disabled={loading}>{loading ? ( <Spinner
as="span"
animation="border"
size="sm"
role="status"
aria-hidden="true"/> ) : 'Muat Ulang'}</Button>
</Form>
<div>
<Button variant='success' onClick={() => { setShowModal(true) }}>Daftar Akun</Button>
</div>
</div>
<TableUserInfo users={usersdata}/>
</Card.Body>
</Card>
{
showModal ? <ModalCreate show={handleShowModal} onClose={handleCloseModal} action={registerUser} /> : null
}
</Container>
)
}
export default PengaturanPengguna;
and here's my mutation :
const REGISTER_USER = gql`
mutation($input: RegisterInput!) {
register(input: $input) {
username
email
full_name
phone
address
group_id
}
}
`;
Error :
I got this error
Also, Network Status Tabs :
I've been try any solution but it still not working, any help will be appreciated, thank you
If you are getting validation error from apollo for required fields then check the form fields may be name attribute is missing and value is not storing inside your state.

how to do validation for a antd Text (typography) component?

It seems that we couldn't add validation for antd editable <Text> (typography).
The component doesn't accept value props like <Input> component. How do we do validation in that case?
Code:
const [title, setTitle] = useState("Battle");
<>
<Form id="myForm" name="basic" onFinish={onSubmit}>
<Form.Item
name="title"
rules={[
{
required: true,
message: "Please input your title!"
}
]}
>
<Text editable>{title}</Text>
</Form.Item>
</Form>
<Button form="myForm" key="formSubmit" htmlType="submit" type="primary">
Create
</Button>
</>
Above code validation works but if the data is still there, it show validation error.
Codesandbox link : https://codesandbox.io/s/basic-antd-4-16-9-forked-o8nxdl?file=/index.js
Here is a code that does some simple validations
function reducer (action , state) {
switch (action.type){
case 'title':
return {...state , data : { ...state.data , title : action.payload }
, errors : { ...state.errors
, title : title.length > 3 null : '😈'} } // title length must be > 3
}
}
const [state , dispatch] = useReducer (reducer , {data : {} , errors : {})
console.log (state)
return ( <> <Form.Item
name="title"
rules={[
{
required: true,
message: "Please input your title!"
}
]}
onChange = {(e) => dispatch ({type : 'title' , payload : e.target.value})
>
<Text editable>{title}</Text>
</Form.Item> </>)
Before submitting make sure all errors must be null
you can handle it using the onChange like this working demo is here
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Form, Button, Input, Typography } from "antd";
import SecForm from "./SecForm";
const { Text } = Typography;
const App = () => {
const [title, setTitle] = useState('Battle');
const data = ["1", "2", "3"];
const onHandleChange = (event) => {
setTitle(event);
};
const onSubmit = (e) => {
e.preventDefault();
console.log("Submitted");
};
return (
<>
<Form id="myForm" name="basic" onFinish={onSubmit}>
<Form.Item
label="name"
name="name"
rules={[
{
required: true,
message: "Please input your name!"
}
]}
>
<Input placeholder="Name" />
</Form.Item>
<Form.Item
label="rank"
name="rank"
rules={[
{
required: true,
message: "Please input your rank!"
}
]}
>
<Input placeholder="Rank" />
</Form.Item>
<Form.Item
name="title"
valuePropName={title}
rules={[
{
required: title?.length < 1,
message: "Please input your title!"
}
]}
>
<Text editable={{ onChange: onHandleChange }}>{title}</Text>
</Form.Item>
{data.map((d, index) => (
<SecForm index={index} />
))}
</Form>
<Button form="myForm" key="formSubmit" htmlType="submit" type="primary">
Create
</Button>
</>
);
};
ReactDOM.render(<App />, document.getElementById("container"));

Enable or Disable Form button in React based on condition

I'm new to React and going through a course online. I came across this issue, where i wanted to enable or disable a button based on values present in the text field. If it is create/edit option then submit button should be disabled by default but if any value is entered or edited the submit button should be enabled.
if you want to enable or disable your button on condition base then all you have to do is add ternary operator in your jsx like this
<button id='my_button' disabled ={(activityChanged)?true:false}>Click Me</button>
This is what I tried. Created const [activityChanged, setActivityChanged] = useState(false); by keeping the initial value of activityChanged to false. And applied disabled attribute to the button as shown below.
<Button
disabled={!activityChanged}
loading={submitting}
floated="right"
positive
type="submit"
content="Submit"
/>
And updated the value of activityChanged on onChange event of text input as shown below
const handleInputChange = (
event: FormEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = event.currentTarget;
setActivity({ ...activity, [name]: value });
setActivityChanged(true)
};
Below is the complete code:
import React, { FormEvent, useState } from "react";
import { Button, Form, Segment } from "semantic-ui-react";
import { IActivity } from "../../../app/models/activity";
import { v4 as uuid } from "uuid";
interface IProps {
setEditMode: (editMode: boolean) => void;
activity: IActivity;
createActivity: (activity: IActivity) => void;
editActivity: (activity: IActivity) => void;
submitting: boolean;
}
const ActivityForm: React.FC<IProps> = ({
setEditMode,
activity: initialFormState,
createActivity,
editActivity,
submitting,
}) => {
const initializeForm = () => {
if (initialFormState) {
return initialFormState;
} else {
return {
id: "",
title: "",
category: "",
description: "",
date: "",
city: "",
venue: "",
};
}
};
const [activity, setActivity] = useState<IActivity>(initializeForm);
const [activityChanged, setActivityChanged] = useState(false);
const handleSubmit = () => {
console.log(activity);
if (activity.id.length === 0) {
let newActivity = {
...activity,
id: uuid(),
};
createActivity(newActivity);
} else {
editActivity(activity);
}
};
const handleInputChange = (
event: FormEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = event.currentTarget;
setActivity({ ...activity, [name]: value });
setActivityChanged(true)
};
return (
<Segment clearing>
<Form onSubmit={handleSubmit}>
<Form.Input
onChange={handleInputChange}
name="title"
placeholder="Title"
value={activity.title}
/>
<Form.TextArea
onChange={handleInputChange}
name="description"
rows={2}
placeholder="Description"
value={activity.description}
/>
<Form.Input
onChange={handleInputChange}
name="category"
placeholder="Category"
value={activity.category}
/>
<Form.Input
onChange={handleInputChange}
name="date"
type="datetime-local"
placeholder="Date"
value={activity.date}
/>
<Form.Input
onChange={handleInputChange}
name="city"
placeholder="City"
value={activity.city}
/>
<Form.Input
onChange={handleInputChange}
name="venue"
placeholder="Venue"
value={activity.venue}
/>
<Button
disabled={!activityChanged}
loading={submitting}
floated="right"
positive
type="submit"
content="Submit"
/>
<Button
onClick={() => setEditMode(false)}
floated="right"
type="button"
content="Cancel"
/>
</Form>
</Segment>
);
};
export default ActivityForm;

Setting value on TextField input text become non editable

I am creating a form for updating the data from mongodb I was able to fetch the data and added onchange if the currentId exist then all the data will populate on the form but, my problem is I cannot edit or I cannot type anything on the input to edit the value. I really need your eyes to see something that have missed or missed up. Thanks in advance y'all.
Profile container
import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getProfile } from '../../../actions/profile'; //fetch method
import Profile from './Profile';
function Index() {
const dispatch = useDispatch();
const posts = useSelector((state) => state.posts);
const currentId = useState(null);
useEffect(() => {
dispatch(getProfile());
}, [currentId, dispatch]);
return (
<div className="custom-container">
{posts.map((profile) => (
<div key={profile._id}>
<Profile profile={profile} currentId={currentId} />
</div>
))}
</div>
);
}
export default Index;
Profile form component
import './Profile.css';
import { React, useState, useEffect } from 'react';
import Button from 'react-bootstrap/Button';
import { TextField } from '#material-ui/core';
import { useDispatch, useSelector } from 'react-redux';
import { updateProfile } from '../../../actions/profile';
const Profile = ({ profile, currentId }) => {
const dispatch = useDispatch();
currentId = profile._id;
const [postData, setPostData] = useState(
{
profile: {
name: "",
description: "",
email: "",
number: "",
}
}
);
const post = useSelector((state) => currentId ? state.posts.find((p) => p._id === currentId) : null);
useEffect(() => {
if(post) setPostData(post);
}, [post])
const handleSubmit = (e) => {
e.preventDefault();
if(currentId) {
dispatch(updateProfile(currentId, postData));
}
}
// const [ImageFileName, setImageFileName] = useState("Upload Profile Picture");
// const [fileName, setFileName] = useState("Upload CV");
return (
<form autoComplete="off" noValidate className="form" onSubmit={handleSubmit}>
<TextField
id="name"
name="name"
className="name"
label="Full Name"
variant="outlined"
value={postData.profile.name}
onChange={(e) => setPostData({ ...postData, name: e.target.value })}
/>
<TextField
id="outlined-multiline-static"
label="Multiline"
multiline
rows={4}
variant="outlined"
size="small"
className="mb-3"
name="description"
value={postData.profile.description}
onChange={(e) => setPostData({ ...postData, description: e.target.value })}
fullWidth
/>
<TextField
id="email"
label="Email"
variant="outlined"
size="small"
className="mb-3"
name="email"
value={postData.profile.email}
onChange={(e) => setPostData({ ...postData, email: e.target.value })}
/>
<TextField
id="phone"
label="Phone Number"
variant="outlined"
size="small"
name="phone"
value={postData.profile.number}
onChange={(e) => setPostData({ ...postData, number: e.target.value })}
/>
<Button variant="light" type="submit" className="Save">Save</Button>
</form>
);
}
export default Profile;
If you'd look at the name field for example, you can see the value is postData.profile.name while onChange your setting postData.name.
Try setting the profile object, for example:
onChange={(e) => setPostData({ ...postData, profile: { ...postData.profile, name: e.target.value } })}

React ant design reset only one input filed

Im using my project for React ant design 4 . I have some conflict on the form . I want to know how to reset only one (Note) field any one know the solution
Thanks
stazkblitz here
code here
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Form, Input, Button, Select } from 'antd';
const { Option } = Select;
const layout = {
labelCol: {
span: 8,
},
wrapperCol: {
span: 16,
},
};
const tailLayout = {
wrapperCol: {
offset: 8,
span: 16,
},
};
const Demo = () => {
const [form] = Form.useForm();
const onGenderChange = (value) => {
switch (value) {
case 'male':
form.setFieldsValue({
note: 'Hi, man!',
});
return;
case 'female':
form.setFieldsValue({
note: 'Hi, lady!',
});
return;
case 'other':
form.setFieldsValue({
note: 'Hi there!',
});
return;
}
};
const onFinish = (values) => {
console.log(values);
};
const onReset = () => {
form.resetFields();
};
const onFill = () => {
form.setFieldsValue({
note: 'Hello world!',
gender: 'male',
});
};
return (
<Form {...layout} form={form} name="control-hooks" onFinish={onFinish}>
<Form.Item
name="note"
label="Note"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item
name="gender"
label="Gender"
rules={[
{
required: true,
},
]}
>
<Select
placeholder="Select a option and change input text above"
onChange={onGenderChange}
allowClear
>
<Option value="male">male</Option>
<Option value="female">female</Option>
<Option value="other">other</Option>
</Select>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.gender !== currentValues.gender}
>
{({ getFieldValue }) => {
return getFieldValue('gender') === 'other' ? (
<Form.Item
name="customizeGender"
label="Customize Gender"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
) : null;
}}
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
Submit
</Button>
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
<Button type="link" htmlType="button" onClick={onFill}>
Fill form
</Button>
</Form.Item>
</Form>
);
};
ReactDOM.render(<Demo />, document.getElementById('container'));
You can add an array of namePath in your form.resetFields call
const onReset = () => {
form.resetFields(["note"]);
};
Just tested it with your code and it works : https://stackblitz.com/edit/react-nazmet-jh2cc1?file=index.js
More info : https://ant.design/components/form/#FormInstance

Resources