Pass closeModal from one component to other with react - reactjs

Hi i am trying to close a modal box from another component. I have a component with a list and other with a form.
The error that i get is:
Unhandled Rejection (TypeError): _this2.closeModal is not a function
The List file with the modal commands has:
closeModal = () => this.setState({ isOpen: false });
render() {
const { closeModal } = this.state
...
<Modal show={this.state.isOpen} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Adicionar / Editar</Modal.Title>
</Modal.Header>
<Modal.Body>
<CategoryForm
id={this.state.id || null}
closeModal={closeModal}
/>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.closeModal}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
// some code
}
the file with form, that will close the modal after saving info in the database is
class CategoryForm extends Component {
constructor(props) {
super(props)
this.state = {
closeModal: props.closeModal
}
}
handleSubmit(event) {
event.preventDefault()
let category = {
title: this.state.category.title,
}
Api.saveCategory(category, this.state.category.id)
.then(response => {
const [error, errors] = response
if (error) {
this.setState({
errors: errors
})
} else {
this.setState(
this.closeModal()
)
}
})
}
//some code
render() {
<Form onSubmit={this.handleSubmit} >
<FormGroup>
<Label for="title">Title</Label>
<Input type="text" name="title" id="title" value={category.title} placeholder="Enter title" onChange={this.setTitle} />
</FormGroup>
<FormGroup>
<Label for="slug">Slug</Label>
<Input type="text" name="slug" id="slug" value={category.slug} placeholder="Enter slug" onChange={this.setSlug} />
</FormGroup>
<Button color="success">Submit</Button>
</Form>
}

In the list file create a command that call the function close modal:
closeModal = () => this.setState({ isOpen: false });
addCategory() {
this.closeModal()
}
render() {
...
<Modal show={this.state.isOpen} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Adicionar / Editar</Modal.Title>
</Modal.Header>
<Modal.Body>
<CategoryForm
id={this.state.id || null}
addCategory={this.addCategory}
/>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.closeModal}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
// some code
}
In the form, props the function at the handleSubmit:
handleSubmit(event) {
event.preventDefault()
let category = {
title: this.state.category.title,
slug: this.state.category.slug,
}
Api.saveCategory(category, this.state.category.id)
.then(response => {
const [error, errors] = response
if (error) {
this.setState({
errors: errors
})
} else {
this.setState(
)
}
})
const form = event.target;
this.props.addCategory( id, slug, title);
form.reset();
}

Related

How to fix update Modal not showing this.state.value

I am trying to create a modal that handles updates, but it's not showing {this. state. value}
state={
name: '',
businessName: '',
show: false,
}
showModal(e) {
if (e) {
this.setState({ show: true });
}
}
showEditModal(e) {
const { user } = this.props.auth;
const email=user.email
axios.get(`/api/v1/auth/userdetails/${email}`)
.then(
(res) => {
console.log(res.data) // res.data actually has data from API
let user = res.data
this.setState ({
id:user.id,
name:user.name,
businessName:user.businessName,
})
this.setState({
show: true,
});
console.log(this.state.name) // i get undefined
},
(err) => {
alert('An error occured! Try refreshing the page.', err);
}
);
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = (e) => {
e.preventDefault();
const {
_id,
name,
businessName,
} = this.state;
const userDetail = {
_id,
name,
businessName,
};
console.log(userDetail);
axios.post(`/api/v1/auth/update/${_id}`, userDetail).then(
(res) => {
Swal.fire({
title: 'Profile ',
text: 'Update successful!',
icon: 'success',
confirmButtonText: 'Ok'
})
},
(err) => {
alert('An error occured! Try submitting the form again.', err);
}
);
};
hideModal = () => {
this.setState({
show: false,
name:'',
businessName:'',
});
};
ModalForm=()=>{
return <div style={{ backgroundColor: 'white' }}>
<Modal
{...this.props}
show={this.state.show}
onHide={this.hideModal}
dialogClassName='custom-modal'
>
<Modal.Header closeButton>
<Modal.Title
id='contained-modal-title-lg '
className='text-center'
>
Update Profile
</Modal.Title>
</Modal.Header>
<Modal.Body className='modal-contentx'>
<Form horizontal onSubmit={this.onSubmit}>
<FormGroup controlId='formHorizontalEmail'>
<Col smOffset={4} sm={6}>
<FormControl
type='Text'
backgroundColor='grey'
placeholder='name'
name='name'
value={this.state.name}
onChange={this.onChange}
/>
</Col>
</FormGroup>
<FormGroup controlId='formHorizontalPassword'>
<Col smOffset={4} sm={6}>
<FormControl
type='text'
placeholder=''
name='businessName'
value={this.state.businessName}
onChange={this.onChange}
/>
</Col>
</FormGroup>
<FormGroup>
<Col smOffset={5} sm={6}>
<Button type='submit' bsStyle='primary'>
Add
</Button>
</Col>
</FormGroup>
</Form>
</Modal.Body>
</Modal>
</div>
<ButtonGroup>
<Button className="btn-fill" color="primary" type="submit">
Save
</Button>
<Button className="btn-fill" onClick={(e) => this.showEditModal(e)}>
Update
</Button>
</ButtonGroup>
}
render(){
return (
<div>
// Add form is placed here
</div>
<div>
// modal form is placed here
{this.ModalForm()}
</div>
)
}
the modal comes up onClick, but fails to show any value. When i do console.log(this.state.name) for instance i get undefined?!
I need the Modal to be populated with the value from the state. The response object from the console contains the data that i am using to update the state through setState().
i guess something is off though, but cant figure it out

Why this code has findDOMNode warning first time open the dialog?

Always got this error when the first time open this dialog:
Warning: findDOMNode is deprecated in StrictMode. findDOMNode was
passed an instance of Transition which is inside StrictMode. Instead,
add a ref directly to the element you want to reference
import React, { Component } from "react";
import {Button, Modal, Form} from "react-bootstrap";
class ClusterBar extends Component {
state = { show: false, clusterName: '', clusterConfigure: '' };
handleClose = () => this.setState({show: false});
handleShow = () => this.setState({show: true});
handleSave = () => {
this.setState({show: false});
console.log(this.state.clusterName, this.state.clusterConfigure);
}
handleClusterNameChange = (event) => {
this.setState({clusterName: event.target.value});
}
handleClusterConfigureChange = (event) => {
this.setState({clusterConfigure: event.target.value});
}
render() {
return(
<>
<div className="list-group">
<Button className="list-group-item list-group-item-action">cluster One</Button>
<Button className="list-group-item list-group-item-action">cluster Two</Button>
<Button className="list-group-item list-group-item-action">cluster Three</Button>
<Button className="list-group-item list-group-item-action" onClick={this.handleShow}>+</Button>
</div>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add a cluster</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formClusterName">
<Form.Label>Cluster Name</Form.Label>
<Form.Control type="text" onChange={this.handleClusterNameChange} />
</Form.Group>
<Form.Group controlId="formClusterConfigure">
<Form.Label>Connnection Configure</Form.Label>
<Form.Control as="textarea" rows="3" onChange={this.handleClusterConfigureChange} />
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.handleClose}>
Cancel
</Button>
<Button variant="primary" onClick={this.handleSave}>
Save
</Button>
</Modal.Footer>
</Modal>
</>
)
}
}
export default ClusterBar

Browser not previewing image that was previously uploaded

I have a component in React that is responsible for image preview. I also have an option for removing the image. I have noticed that if I have uploaded an image, and then removed it, that I can't preview it if I want to upload it again. Why is that happening?
This is my component:
class MediaPlaceholder extends Component {
constructor(props) {
super(props)
this.state = {
fileUrl: null
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
fileUrl: URL.createObjectURL(event.target.files[0])
})
}
removeImage() {
this.setState((prevState) => {
URL.revokeObjectURL(prevState.fileUrl);
return {fileUrl: null};
});
}
render() {
const {classes} = this.props;
const {fileUrl} = this.state;
return (
<Paper className={classes.media}>
{fileUrl &&
<div className={classes.imageWrapper}>
<IconButton aria-label="Clear" className={classes.iconButton} onClick={() => this.removeImage()}>
<ClearIcon/>
</IconButton>
<img src={fileUrl} className={classes.image}/>
</div>
}
<input
accept="image/*"
className={classes.input}
id="upload-file"
type="file"
onChange={(event) => this.handleChange(event)}
/>
<label htmlFor="upload-file">
<Button component="span">
Add media...
</Button>
</label>
</Paper>
);
}
}

pristine function not working redux form

I started working with redux-form along with react-bootstrap. I have give validation in my form my custom validation is working fine but I have given pristine condition from this doc it is not working for me. below is my code for that let me know where I went wrong? do I need to add anything?
If anyone let me know what render field does for me?
const renderField = ({
input,
label,
type,
meta: { touched, error, warning }
}) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched &&
((error && <span>{error}</span>) ||
(warning && <span>{warning}</span>))}
</div>
</div>
);
class Duplicate extends React.Component {
constructor(...args) {
super(...args);
this.state = {
open: false,
showModal: false
};
}
saveDuplicate = value => {
if ('[default]'.includes(value.duplicateName)) {
throw new SubmissionError({
duplicateName: 'User does not exist',
_error: 'Login failed!'
});
}
console.log('value on submit', value);
};
close = () => this.setState({ showModal: false });
openModal = () => this.setState({ showModal: true });
render() {
console.log('this props in duplicate', this.props);
const required = value => (value ? undefined : 'Required');
const { handleSubmit, pristine, reset, submitting } = this.props;
return (
<div className="scenario_btn">
<Button
onClick={this.openModal}
bsStyle="danger"
className="scenario_mangt"
>
Duplicate
</Button>
<Modal
aria-labelledby="modal-label"
show={this.state.showModal}
onHide={this.close}
>
<form onSubmit={handleSubmit(this.saveDuplicate)}>
<Field
name="duplicateName"
type="text"
component={renderField}
label="name"
validate={[required]}
/>
<div>
<button type="submit" disabled={submitting}>
Save
</button>
<button
type="button"
disabled={pristine || submitting}
onClick={reset}
>
Cancel
</button>
</div>
</form>
</Modal>
</div>
);
}
}
export default reduxForm({
form: 'duplicatForm' // a unique identifier for this form
})(Duplicate);

How to submit form component in modal dialogue using antd react component library

In my component's render method I have antd Modal component as a parent and antd Form component as a child:
render() {
const myForm = Form.create()(AddNewItemForm);
...
return (
...
<Modal
title="Create new item"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
wrapClassName="vertical-center-modal"
okText="Save new item"
width="600"
>
<myForm />
</Modal>
...
How can I submit my form by clicking the Modals Save button?
There is a new solution that looks much cleaner:
<Form id="myForm">
...
<Modal
...
footer={[
<Button form="myForm" key="submit" htmlType="submit">
Submit
</Button>
]}
>
<CustomForm />
</Modal>
This works because of the Button's form attribute. Browser support
Original solution's author: https://github.com/ant-design/ant-design/issues/9380
My solution is using hooks
import { Button, Modal, Form } from 'antd';
export default function ModalWithFormExample() {
const [visible, setVisible] = useState(false);
const [form] = Form.useForm();
const showModal = () => {
setVisible(true)
}
const handleSubmit = (values) => {
console.log(values)
}
const handleCancel = () => {
setVisible(false)
form.resetFields()
};
return (
<>
<Button onClick={showModal}>Open Modal</Button>
<Modal visible={visible} onOk={form.submit} onCancel={handleCancel}>
<Form form={form} onFinish={handleSubmit}>
{/* Any input */}
</Form>
</Modal>
</>
)
}
You can study official example: https://ant.design/components/form/#components-form-demo-form-in-modal
My solution was to wrap modal dialogue and form components in a new wrapper parent component in which I validate the child form component in handleCreate method. I have used the ref attribute to reference the myForm child component inside the FormOnModalWrapper component. I am passing the parent handlers via props from the wrapper parent component to myForm component instance.
class FormOnModalWrapper extends React.Component {
...
constructor(props) {
this.state =
{
visible: false
....
}
...
showModal = () => {
this.setState({
visible: true,
});
}
handleCreate = () => {
const form = this.form;
form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
form.resetFields();
this.setState({ visible: false });
});
}
saveFormRef = (form) => {
this.form = form;
}
render() {
...
const myForm= Form.create()(CrateNewItemFormOnModal);
...
return (
<div>
<Button onClick={this.showModal}>Add</Button>
<myForm
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
ref={this.saveFormRef}
/>
</div>
);
}
In CrateNewItemFormOnModal component class I have a modal dialogue component as a parent and form component as a child:
export default class AddNewItemForm extends React.Component {
render() {
...
const { visible, onCancel, onCreate, form } = this.props;
...
return (
<Modal
title="Create new item"
visible={visible}
onOk={onCreate}
onCancel={onCancel}
okText="Create"
>
<Form>
...
</Form>
</Modal>
);
}
My solution was to disable the modal's footer and create my own submit button:
<Modal footer={null}>
<Form onSubmit={this.customSubmit}>
...
<FormItem>
<Button type="primary" htmlType="submit">Submit</Button>
</FormItem>
</Form>
</Modal>
No need to wrap the modal with this solution.
Now, react hooks are out you can achieve the same thing using hooks also. By creating a wrapper component for the modal and used that component where the form is.
Wrapper Component:
<Modal
visible={state}
centered={true}
onCancel={() => setState(false)}
title={title}
destroyOnClose={true}
footer={footer}>
{children}
</Modal>
Form Component:
<WrapperModal
state={modalState}
setState={setModal}
title='Example Form'
footer={[
<button onClick={handleSubmit}>
SUBMIT
<button/>
]}>
<Form>
<Form.Item label='name '>
{getFieldDecorator('name ', {
rules: [
{
required: true,
message: 'please enter proper name'
}
]
})(<Input placeholder='name'/>)}
</Form.Item>
</Form>
</WrapperModal>
here i had created a wrapper modal component which have all the necessary api for the modal, also i am creating a custom buttons for my modal
My solution 1st solution
...
handleOk = (e) => {
e.preventDefault();
this.form.validateFields((err, values) => {
//do your submit process here
});
}
//set ref form
formRef = (form) => {
this.form = form;
}
render() {
const myForm = Form.create()(AddNewItemForm);
...
return (
...
<Modal
title="Create new item"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
wrapClassName="vertical-center-modal"
okText="Save new item"
width="600"
>
<myForm
ref={this.formRef}
/>
</Modal>
...
or you can use this solution
...
handleOk = (e) => {
e.preventDefault();
this.form.validateFields((err, values) => {
//do your submit process here
});
}
render() {
const myForm = Form.create()(AddNewItemForm);
...
return (
...
<Modal
title="Create new item"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
wrapClassName="vertical-center-modal"
okText="Save new item"
width="600"
>
<myForm
wrappedComponentRef={(form) => this.formRef = form}
/>
</Modal>
...
The idea is to set the ref for wrapped the form component.
Please see the reference below.
Reference
Simple way to do this in 2021 is making customized footer for modal
import { useState } from 'react'
import { Modal, Button, Form, Input } from 'antd'
export default function BasicModal() {
const [form] = Form.useForm()
const [isModalVisible, setIsModalVisible] = useState(false)
const showModal = () => setIsModalVisible(true)
const handleCancel = () => {
setIsModalVisible(false)
form.resetFields()
}
const handleOk = () => {
form.submit()
}
const onFinish = () => {
console.log('Form submited!')
setIsModalVisible(false)
}
return (
<>
<Button type="primary" onClick={showModal}>
Show Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
footer={[
<Button key="back" onClick={handleCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={handleOk}>
Submit
</Button>,
]}
>
<Form labelCol={{ xs: { span: 6 } }} wrapperCol={{ xs: { span: 12 } }} form={form} onFinish={onFinish} scrollToFirstError>
<Form.Item name="input1" label="Input 1" rules={[{ required: true, message: "This field is required." }]}>
<Input />
</Form.Item>
<Form.Item name="input2" label="Input 2" rules={[{ required: true, message: "This field is required." }]}>
<Input />
</Form.Item>
</Form>
</Modal>
</>
)
}

Resources