How can I connect between my form and modal? - javascript

I made a form project with react. My form is working well for now but I want add bootstrap modal to my form.
When I click the enter button, I want to show a modal. I found modal example on the web but I can't establish connection between form and modal. This is my form
import React from "react";
import { useState } from "react";
const Contact = () => {
const [showModal, setShowModal] = useState(false);
const [inputValue, setInputValue] = useState("");
const [emailValue, setEmailValue] = useState("");
const [phoneNumberValue, setPhoneValue] = useState("");
const [countryValue, setCountryValue] = useState("");
const buttonOnClick = () => {
if (inputValue === "" || emailValue === "" || phoneNumberValue === "") {
setShowModal(false)
} else {
setShowModal(true)
setInputValue("")
}
console.log(`Form submitted, ${showModal}`);
}
return (
<div className="main">
<form >
<div className="baslik">
<div className="container center">
<h1>Contact Form</h1>
</div>
</div>
<div className="field" >
<label className="text"> Name And Surname: </label>
<input type="text" className="form" placeholder="Kerem Kurt" required value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
</div>
<div className="field">
<label className="text"> E-mail: </label>
<input type="email" className="form" placeholder="udenditfy#gmail.com" required value={emailValue} onChange={(e) => setEmailValue(e.target.value)} />
</div>
<div className="field">
<label className="text"> Phone Number: </label>
<input type="tel" className="form" pattern="[0-9]*" placeholder="+905373199437" required value={phoneNumberValue} onChange={(e) => setPhoneValue(e.target.value)} />
</div>
<div className="field">
<label className="text" required > Country: </label>
<select className="form" placeholder="Turkiye" required value={countryValue} onChange={(e) => setCountryValue(e.target.value)}>
<option value="Turkiye">Turkiye</option>
<option value="Azerbaijan">Azerbaijan</option>
<option value="Japan">Japan</option>
<option value="Serbia">Serbia</option>
<option value="France">France</option>
</select>
</div>
<button type="button" className="button" onClick={() => buttonOnClick()}> Enter </button>
</form>
</div>
);
};
export default Contact;
And this is modal codes;
import React, { useState } from 'react';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
function Example() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick={handleShow}>
Launch static backdrop modal
</Button>
<Modal
show={show}
onHide={handleClose}
backdrop="static"
keyboard={false}
>
<Modal.Header closeButton>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>
I will not close if you click outside me. Don't even try to press
escape key.
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary">Understood</Button>
</Modal.Footer>
</Modal>
</>
);
}
render(<Example />);

If you want to open your modal after the event "click" in your Form component, you have to import the modal in your form.
For example, your Form is in a component called "Form.jsx" and Modal is in "Modal.jsx" :
Inside Form.jsx, you must import your Modal, move the "show" state into your Form.jsx and pass it in Modal props, just like that :
import Modal from '/path/to/Modal.jsx'
const [show, setShow] = useState(false);
<form>
{children}
</form>
<Modal show={show} setShow={setShow}/>
Inside your Modal.jsx, just change a few things :
function Modal(props){
// remove the show State
// Remove the Button with "handleShow" function.
const handleClose = () => props.setShow(false);
<Modal show={props.show}>
<Button onClick={handleClose}>Close</Button>
</Modal>
}

Welcome to world of react development!
Your question is a classic question about sharing state between components. This is what you refer to as "connection" between components.
The solution is generally referred to as "lifting state up". I highly recommend reading through that if you haven't already.
Example:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { useState } from "react";
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
const root = ReactDOM.createRoot(document.getElementById('root'));
const Contact = ({toggleShow}) => {
return (
<div className="main">
<form >
<button type="button" className="button" onClick={() => toggleShow()}> Show Modal </button>
</form>
</div>
);
};
const MyModal = ({show, toggleShow}) => {
return (
<>
<Modal
show={show}
onHide={toggleShow}
backdrop="static"
keyboard={false}
>
<Button variant="secondary" onClick={toggleShow}>
Close
</Button>
</Modal>
</>
);
}
const App = () => {
const [show, setShow] = useState(false);
const toggleShow = () => setShow(!show);
return (
<>
<Contact toggleShow={toggleShow}/>
<MyModal show={show} toggleShow={toggleShow}/>
</>
)
}
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Explanation:
The general idea is to share the show state of the Modal as well as the state toggler toggleShow() between our <Contact> and <MyModal> components.
We can easily achieve this:
create a new parent component <App> (the name is arbitrary) where we define the show state and the toggler function.
pass the state and toggler into the modal: <MyModal state={state} toggleShow={toggleShow} />.
the form only needs the toggler: <Form toggleShow={toggleShow} />
Note that toggleShow can also be split into separate handleShow and handleClose function, but this approach saves us a few lines.

Related

Not able to pass data between components in React

I am making a simple calculator app with react in which I want to display the value of the button component in the Display component, but I'm not getting how to do this
Here are the Codes :
Code Of Calculator Component:
import React from "react";
import "./Calculator.css";
import Button from "./Button";
import { useState } from "react";
import Display from "./Display";
const Calculator = () => {
const [Data, setData] = useState("");
return (
<>
<center>
<h1 className="title">Calculator</h1>
<br />
<Display data={Data} />
<div className="btncontainer">
<Button name="+" onClick={() => setData("+")}></Button>
<Button name="-" onClick={() => setData("-")}></Button>
<Button name="/" onClick={() => setData("/")}></Button>
<Button name="X" onClick={() => setData("X")}></Button>
<Button name="1" onClick={() => setData("1")}></Button>
<Button name="2" onClick={() => setData("2")}></Button>
<Button name="3" onClick={() => setData("3")}></Button>
<Button name="4" onClick={() => setData("4")}></Button>
<Button name="5" onClick={() => setData("5")}></Button>
<Button name="6" onClick={() => setData("6")}></Button>
<Button name="7" onClick={() => setData("7")}></Button>
<Button name="8" onClick={() => setData("8")}></Button>
<Button name="9" onClick={() => setData("9")}></Button>
<Button name="0" onClick={() => setData("0")}></Button>
<Button name="=" onClick={() => setData("=")}></Button>
</div>
</center>
</>
);
};
export default Calculator;
Code Of Display Component:
import React from "react";
const Display = (props) => {
console.log("Props in display : ", props);
const handleOnChange = (e) => {
props.data = e.target.value;
};
return (
<input type="text" value={props.data} onChange={handleOnChange} readOnly />
);
};
export default Display;
Code Of Button Component:
import React from "react";
import "./Button.css";
const Button = (props) => {
return (
<input
type="button"
className="btn"
value={props.name}
onClick={props.onClick(props.name)}
></input>
);
};
export default Button;
As I've just started learning React, please ignore my silly mistakes
In the Button component, if you want to pass an argument to the function, you want to set the onClick to an arrow function.
onClick={()=>props.onClick(props.name)}
In the Display component, you should pass in the setData function and use that for the onChange.
onChange={(e)=>setData(e.target.value)}
If you want a string of all the buttons clicked, you can change the button onClick to add to the current value of data instead of replacing it.
For example, for button 5:
onClick={()=>setData(data+'5'}

TypeError: Cannot read properties of undefined (reading 'data')

I am working on a web project using reactjs and I faced some problems exactly 2.
The first one is when I want to send a request to my api using axios.
This is what I have done so far:
import auction1 from '../../Images/auction1.png'
import {useState} from 'react';
import './HomeScreen.css'
import {Button, Modal } from 'react-bootstrap';
import axios from 'axios';
const HomeScreen = ()=>{
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const [img, setImg] = useState("");
const [name, setName] = useState("");
const [price, setPrice] = useState(null);
const [deadline, setDeadLine] = useState("");
const [description, setDescription] = useState("");
const [message, setMessage] = useState(null);
const [error, setError] = useState(false);
const handleSubmit = async(e)=>{
e.preventDefault();
try{
const config = {
headers: {
"Content-Type": "application/json",
},
};
const {data} = await axios.post("http://localhost:7500/api/users/posts"
,{name, img, deadline, price, description},config);
console.log(data);
}catch{
setError(error.response.data.message);
}
};
return(
<div className="container bg">
<img src ={auction1} className='landing-image' />
<div style={{marginLeft:460}}>
<Button variant="primary" onClick={handleShow}>
Create Post
</Button>
</div>
<Modal show={show} onHide={handleClose}>
<form onSubmit={handleSubmit}>
<Modal.Header closeButton>
<Modal.Title>Create Post</Modal.Title>
</Modal.Header>
<Modal.Body>
<form >
<div className="form-group">
<label>Post Name:</label>
<input type="text" className="form-control" placeholder="Enter Name"
value={name} onChange={(e)=> setName(e.target.value)}/>
</div>
<div className="form-group">
<label>Post Images:</label>
<input type="file" className="form-control" multiple onChange="readURL(this)" accept="Image/*"
value={img} onChange={(e)=> setImg(e.target.value)}/>
</div>
<div>
<label>Price:</label>
<input type="number" className="form-control" placeholder="TND"
value={price} onChange={(e)=> setPrice(e.target.value)}/>
</div>
<div>
<label>DeadLine:</label>
<input type="date" className="form-control"
value={deadline} onChange={(e)=> setDeadLine(e.target.value)}/>
</div>
<div>
<label>Description:</label>
<textarea className="form-control" rows="3"
value={description} onChange={(e)=> setDescription(e.target.value)}/>
</div>
</form>
</Modal.Body>
<Modal.Footer>
<button type="submit" className="btn btn-primary" data-bs-dismiss="modal" onClick={handleClose} >
Save Post
</button>
<button type="submit" className="btn btn-secondary" data-bs-dismiss="modal" onClick={handleClose}>
Close
</button>
</Modal.Footer>
</form>
</Modal>
</div>
)
};
export default HomeScreen;
<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>
The Piece of code above is my Home Component in which I have a popup form that shows up when I click on create post button then after filling the form I am getting this error on the console:
The error I had
And a last thing even with unsuccessful submit when I click on the create button again to refill the form I get this type of error:
The second error I had
I would be so grateful if you give a hand on this.

React.js mdbottstrap show Modal with click

I would like to open a modal with a click. The button is visible on my page, but unfortunately the modal does not open when you click it.
Unfortunately I haven't found a solution yet how I can solve the problem.
function ModalPage(props) {
const [username, setUsername] = useState();
const [password, setPassword] = useState();
const [showModal, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<MDBContainer>
<MDBBtn rounded onClick={handleShow}>+</MDBBtn>
<MDBModal show={showModal} onHide={handleClose}>
<MDBModalHeader className="text-center" titleClass="w-100 font-weight-bold">Data Input</MDBModalHeader>
<MDBModalBody>
<form className="mx-3 grey-text">
<MDBInput label="ID" group type="text" validate />
<MDBInput label="Username" group type="email" validate error="wrong" success="right"
onChange={(evt) => setUsername(evt.target.value)}
/>
<MDBInput label="Password" group type="text"
onChange={(evt) => setPassword(evt.target.value)}
/>
<MDBInput type="textarea" rows="2" label="Your message" />
</form>
</MDBModalBody>
<MDBModalFooter className="justify-content-center">
<MDBBtn color="unique" onClick={handleClose}>Send
<MDBIcon far icon="paper-plane" className="ml-2" />
</MDBBtn>
</MDBModalFooter>
</MDBModal>
</MDBContainer>
);
}
export default withRouter(ModalPage);
According to this MDB page, the property used to dictate whether or not a modal is being shown is not show, but rather isOpen. Change
<MDBModal show={showModal} onHide={handleClose}>
To
<MDBModal isOpen={showModal} onHide={handleClose}>

Show External Component On Checkbox Click Between Two Stateless Component

Am a bit new to react and redux. I am trying to call/show another stateless component's div from parent component. For example, if I have the below code
const funcA = ({key}) = > {
return (
<div>
<input type="checkbox">
</div>
);
};
export default funcA
const funcB = ({key}) = > {
return (
<React.Fragment>
<div>
<input type="text" placeholder="age" />
</div>
<div id="showThisDiv">
<input type="text" placeholder="age" />
</div>
</React.Fragment>
);
};
export default funcB
I am not trying go with classes. In Stateless components I know how to show/hide a section by using the useState, but I can only do this while in the same component. The issue or rather the challenge, is when I try to show/hide a section from another component. How would I show/hide the div with id showThisDiv in funcB when the checkbox is toggled in funcA?
It's possible using redux, but you also can do it using state and react hooks:
check out this codesandbox: https://codesandbox.io/s/vibrant-driscoll-odqmo
App.js
import React from "react";
import "./styles.css";
import FuncA from "./FuncA";
import FuncB from "./FuncB";
export default function App() {
const [age, setAge] = React.useState(0);
handleInput = (event) => {
console.log(event.target.value);
setAge(age === 0 ? 1 : 0);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<FuncA age={age} onChange={handleInput} />
<FuncB age={age} />
</div>
);
}
FuncA.js
import React from "react";
export default function FuncA(props) {
return (
<>
<label htmlFor="checkbox">
<input type="checkbox" name="age" onChange={props.onChange} value={props.age} />
</label>
</>
);
}
FuncB.js
import React from "react";
export default function FuncB(props) {
return (
<>
{props.age === 0 && <div className="divA">show div a</div>}
{props.age === 1 && <div className="divB">show div b</div>}
</>
);
}
Yeah, is something like this:
EDIT:
// ComponentA.js
const ComponentA = props => <input type="checkbox" onChange={props.onChange} />
// ComponentB.js
const ComponentB = props => (
<>
<div>
<input type="text" placeholder="age" />
</div>
{props.visible && (
<div id="showThisDiv">
<input type="text" placeholder="age" />
</div>
)}
</>
)
// App.js
const App = () => {
const [visible, setVisible] = useState(false);
return (
<>
<ComponentA onChange={() => setVisible(!visible)} />
<ComponentB visible={visible} />
</>
)
}
Now as you want..

React Redux Form: form is submiting with old values

I have a FieldArray in Redux Form that I push objects inside this array and right after that I have a callback to trigger a function to make a POST request.
When I submit the form I get the old values, because the push() method of the Redux Form is an async dispach from redux.
// Parent component
<FieldArray
name="myObjects"
component={ChildComponent}
onSubmitObjects={this.onSubmit} />
// Function
onSubmit = async () => {
const { getFormValues } = this.props;
const data = {
myObjects: getFormValues.myObjects
}
try {
// const contact = await Service.updateUser(data);
} catch (e) {
console.log(e)
}
}
I need to submit the form with the new values added in the array right after the push method.
// Function inside ChildComponent
addNewObject = () => {
const { fields, onSubmitObjects} = this.props;
fields.push({
number: 1,
name: 'Foo',
});
if (onSubmitObjects) {
onSubmitObjects(); // cb() to trigger a function in the parent component
}
}
Is there a way to call the callback with the new values right after the push method?
You should use a form with redux-form handleSubmit to wrap your FieldArray. You can optionally pass your custom submit function (to make API requests, submit validation, etc.) to handleSubmit so it'd look like this <form onSubmit={handleSubmit(this.onSubmit)}> ...
See this example from redux-form official docs:
FieldArraysForm.js
import React from 'react'
import {Field, FieldArray, reduxForm} from 'redux-form'
import validate from './validate'
const renderField = ({input, label, type, meta: {touched, error}}) => (
<div>
<label>{label}</label>
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
</div>
)
const renderHobbies = ({fields, meta: {error}}) => (
<ul>
<li>
<button type="button" onClick={() => fields.push()}>Add Hobby</button>
</li>
{fields.map((hobby, index) => (
<li key={index}>
<button
type="button"
title="Remove Hobby"
onClick={() => fields.remove(index)}
/>
<Field
name={hobby}
type="text"
component={renderField}
label={`Hobby #${index + 1}`}
/>
</li>
))}
{error && <li className="error">{error}</li>}
</ul>
)
const renderMembers = ({fields, meta: {error, submitFailed}}) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>Add Member</button>
{submitFailed && error && <span>{error}</span>}
</li>
{fields.map((member, index) => (
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}
/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"
/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"
/>
<FieldArray name={`${member}.hobbies`} component={renderHobbies} />
</li>
))}
</ul>
)
const FieldArraysForm = props => {
const {handleSubmit, pristine, reset, submitting} = props
return (
<form onSubmit={handleSubmit}>
<Field
name="clubName"
type="text"
component={renderField}
label="Club Name"
/>
<FieldArray name="members" component={renderMembers} />
<div>
<button type="submit" disabled={submitting}>Submit</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
)
}
export default reduxForm({
form: 'fieldArrays', // a unique identifier for this form
})(FieldArraysForm)

Categories