React conditional rendering based on login logout and form submit - javascript

I am trying to initiate conditional rendering based on a form submit that goes to my node router but I am not getting the result. The buttons do not hide the content "ReminderModel" & "Reminder Table" and nothing happens when I submit the login form. I know this isnt the best way to do it but fi someone could point me in the right direction I would appreciate it. I would prefer not to use another plugin for react and would prefer to do it on my own to avoid update conflicts, etc.
import React, { Component } from 'react';
import { Container, Button, Form, Col } from 'react-bootstrap';
import axios from 'axios';
import './App.css';
import ReminderTable from './components/reminderList';
import ReminderModal from './components/modal';
const redColor = {
color: '#e52d2d'
}
class App extends Component {
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.LoginButton = this.LoginButton.bind(this);
this.UponLoggedIn = this.UponLoggedIn.bind(this);
this.NotLoggedIn = this.NotLoggedIn.bind(this);
this.state = {
user:[],
isLoggedIn:false,
username:'',
password:''
};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
LoginButton = props => {
return(
<>
<div id="status"></div>
<Form
className="loginForm"
>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>Username</Form.Label>
<Form.Control
type="text"
name="username"
id="username"
value={this.state.value}
onChange={this.handleChange}
>
</Form.Control>
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
id="password"
name="password"
value={this.state.value}
onChange={this.handleChange}
/>
</Form.Group>
</Form.Row>
<Button className="btn btn-sm btn-light" onClick={this.onSubmit}>
<i style={redColor} className="fas fa-sign-in-alt"></i> Login
</Button>
</Form>
</>
);
}
LogoutButton = props => {
return(
<>
<Button className="btn btn-sm btn-light float-right" onClick={this.NotLoggedIn}>
<i style={redColor} className="fas fa-sign-out-alt"></i> Logout
</Button>
</>
)
}
NotLoggedIn = props => {
return(
<>
<h4 className="text-muted"> Please Log in</h4>
{this.LoginButton()}
</>
)
}
UponLoggedIn = props => {
return(
<>
<ReminderModal />
<p className="text-muted text-center">If new reminder does not show up immediently please refresh page</p>
<ReminderTable />
</>
)
}
ViewScreen = props => {
const isLoggedIn = props.isLoggedIn;
if(isLoggedIn){
return this.UponLoggedIn();
}else {
return this.NotLoggedIn();
}
}
onSubmit = (e) => {
e.preventDefault();
axios.get('api/user')
.then(res => {
const user = res.data[0].username;
const password = res.data[0].password;
const username = this.state.username;
const passwordEntered = this.state.password;
if(user === username && passwordEntered === password){
if(username === '' && passwordEntered === ''){
document.getElementById('status').innerHTML = '<p>Please Enter A Valid Username and Password</p>';
this.NotLoggedIn();
}else{
document.getElementById('status').innerHTML = '<p>Please Enter A Valid Username and Password</p>';
this.NotLoggedIn();
}
this.UponLoggedIn();
}else {
this.NotLoggedIn();
}
})
.catch(error => {
console.log(error);
});
}
render(){
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = this.LoginButton();
} else {
button = this.LogoutButton();
}
return (
<div className="App container">
<h4
className="display-4 mt-4 mb-4 text-center"
>
<i style={redColor}
className="fas fa-asterisk">
</i> Expiration Reminder
</h4>
<Container isLoggedIn={isLoggedIn}>{button}</Container>
</div>
);
}
}
export default App;

You are calling this.NotLoggedIn in onClick handler, which is wrong, because NotLoggedIn returns React component. In the onCLick handler, you need to change state. So you should call this.handleLoginClick and this.handleLogoutClick instead.
Also there are couple of bugs. E.g. you are calling button = this.LoginButton(), but LoginButton functions expects props. You either have to pass the props to the function or you can access it in function as this.props.
Also the way you did it is kind of antipattern, because you are defining multiple components inside App component (LogoutButton, LoginButton etc.). You should split them into multiple classes.

I solved this in a fairly simple way, keep in mind I have a back end with express that searches a predefined username and pass that is why I used axios to fetch that info and check against it in the onSubmit function.
FYI: if you're feeling lost with React or any language really just start by doing projects, that is how I am learning, I took a few Udemy courses but still didn't grasp it, I learned by doing and with each project(big or small) you pick up something new and/or gain a better understanding along the way. Just a little food for thought if you're like me and have a passion but don't know where or how to start.
class App extends Component {
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
user:[],
isLoggedIn:false,
username:'',
password:''
};
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
handleLogoutClick = e => {
this.setState({ isLoggedIn: false })
}
onSubmit = (e) => {
e.preventDefault();
axios.get('API_PATH')
.then(res => {
const user = res.data[0].username;
const password = res.data[0].password;
const username = this.state.username;
const passwordEntered = this.state.password;
if(user === username && passwordEntered === password){
this.setState({ isLoggedIn:true })
}
})
.catch(error => {
console.log(error);
});
}
render(){
return (
<div className="App">
<h4
className="display-4 mt-4 mb-4 text-center"
>
<i style={redColor}
className="fas fa-asterisk">
</i> Expiration Reminder
</h4>
<Container onSubmit={this.onSubmit}>
{this.state.isLoggedIn ? (
<>
<Button className="btn btn-sm btn-light mr-5 float-right" onClick={this.handleLogoutClick}>
<i style={redColor} className="fas fa-sign-out-alt"></i> Logout
</Button>
<ReminderModal />
<p className="text-muted text-center">If new reminder does not show up immediently please refresh page</p>
<ReminderTable />
</>
) : (
<>
<div id="status"></div>
<Form className="loginForm ml-5">
<Form.Row>
<Form.Group as={Col}>
<Form.Label>Username</Form.Label>
<Form.Control
type="text"
name="username"
id="username"
value={this.state.value}
onChange={this.handleChange}
>
</Form.Control>
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
id="password"
name="password"
value={this.state.value}
onChange={this.handleChange}
/>
</Form.Group>
</Form.Row>
<Button className="btn btn-sm btn-light" onClick={this.onSubmit}>
<i style={redColor} className="fas fa-sign-in-alt"></i> Login
</Button>
</Form>
</>
)}
</Container>
</div>
)
}
}
export default App;

Related

How to send data from Modal, Form using react and bootstrap?

I am working with React to POST data in my local database. When I use just the <form>, it works fine. But whenever I am trying to use Modal and Bootstrap, it is giving me an error. I understand that my handleChange/handleSubmit is probably not assigning the values. Just wondering how to send the data from Modal to the handleChange.
Here is my code:
constructor(props) {
super(props);
this.state = {
institutionName: {},
institutionAddress: {},
institutionPhone: {},
allData: [],
};
this.onSubmit = this.handleSubmit.bind(this);
}
// this will look at the API and save the incoming data in allData variable
componentDidMount() {
fetch("/manageInstitution")
.then((res) => res.json())
.then((data) => this.setState({ allData: data }))
.then(console.log(this.state.allData));
}
// this is when submit button is pressed and data will be sent to database using api
handleSubmit(event) {
event.preventDefault();
const data = {
institutionName: this.state.institutionName,
institutionAddress: this.state.institutionAddress,
institutionPhone: this.state.institutionPhone,
};
fetch("/manageInstitution", {
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
})
.then((res) => res.json())
.catch((error) => console.error("Error: ", error))
.then((response) => console.log("Success: ", response));
window.location.reload(false);
}
// when a field changes in the form, do assignment to the state
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value.trim(),
});
};
handleModalShowHide() {
this.setState({ showHide: !this.state.showHide });
}
render() {
const { allData } = this.state;
return (
<div className="body">
<h4>Super Admin View</h4>
<div>
<Button variant="primary" onClick={() => this.handleModalShowHide()}>
Add New Institution
</Button>
<Modal
aria-labelledby="contained-modal-title-vcenter"
show={this.state.showHide}
onSubmit={this.handleSubmit}
>
<Modal.Header
closeButton
onClick={() => this.handleModalShowHide()}
>
<Modal.Title id="contained-modal-title-vcenter">
<h5>Add New Institution</h5>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form className="col-lg-6 offset-lg-3">
<Form.Group className="mb-3">
<Form.Label htmlFor="institutionName">
Institution Name:
</Form.Label>
<Form.Control
type="text"
size="sm"
name="institutionName"
placeholder="Enter Institution Name"
onChange={this.handleChange}
required
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label htmlFor="institutionAddress">
Institution Address:
</Form.Label>
<Form.Control
type="text"
size="sm"
name="institutionAddress"
placeholder="Enter Institution Address"
onChange={this.handleChange}
required
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label htmlFor="institutionPhone">
Institution Phone:
</Form.Label>
<Form.Control
type="tel"
size="sm"
name="institutionPhone"
placeholder="i.e 01911223344"
onChange={this.handleChange}
pattern="[0-9]{3}"
required
/>
</Form.Group>
</Form>
<Modal.Footer>
<Button
variant="secondary"
onClick={() => this.handleModalShowHide()} >Close </Button>
{" "}
<Button
className="btn btn-primary"
type="submit"
onClick={this.handleSubmit}>Submit</Button>
</Modal.Footer>
</Modal.Body>
</Modal>
</div>
);
}
}
export default addNewInstitution;
Here is the error:
TypeError: Cannot read properties of undefined (reading 'state')
handleSubmit
D:/eduBD-React/eduBD/client/src/components/superadmin/manageInstitution.jsx:30
27 | event.preventDefault();
28 |
29 | const data = {
> 30 | institutionName: this.state.institutionName,
31 | institutionAddress: this.state.institutionAddress,
32 | institutionPhone: this.state.institutionPhone,
33 | };
You need to bind or use an Arrow function to have this to point to
correct reference refer docs here
class App extends React.Component {
state = {
name: "hello"
};
handleChangeWithArrow = () => { // use this way to avoid such errors
console.log(this.state.name);
this.setState({ name: "helloo Im changed" });
};
handleChange() {
// need to bind this to work or use an arrow function
console.log(this.state.name);
this.setState({ name: "helloo Im changed" });
}
render() {
return (
<div>
<button onClick={this.handleChange}>Error Produced on Click</button>
<button onClick={this.handleChangeWithArrow}>
Click Me to change Name
</button>
{this.state.name}
</div>
);
}
}
ReactDOM.render(<App/>,document.querySelector('#root'))
<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>
<div id="root"></div>

How to do state operations in function in react without class

this is my React worksection.js file and its function made instead of class
export default function WorkSection() {
now i need to do here constructor to initialise state and do function operations which i'll call on button click
return (
<div className={classes.section}>
<GridContainer justify="center">
<GridItem cs={12} sm={12} md={8}>
<h2 className={classes.title}>Work with us</h2>
<h4 className={classes.description}>
BAIOS BAY LLP is looking for collaborations with you, Contact us
today !
</h4>
<form onSubmit={this.handleSubmit}>
<GridContainer>
<GridItem xs={12} sm={12} md={6}>
<CustomInput
labelText="Your Name"
id="name"
onChange={this.handleChange}
defaultValue={this.state.name}
formControlProps={{
fullWidth: true
}}
/> </GridItem> </GridContainer>
</div>
);
}
this is my form where i am submitting name and will add button click so how can i initialise state and functions to call onclick functions where
my functions are as :
constructor(props) {
super(props);
this.state = {
name : ''}
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
handleClick = event => {
this.setState({
[event.target.id]: event.target.checked
});
}
handleSubmit = event => {
event.preventDefault();
if (this.state.username === '') {
this.showMessage('Info', "Username is empty");
return;
}
}
i need to place this function and i did it with class worksection but how to do it with export default function Worksection()
The thing you're probably looking for called react hooks. They allow you to use state management in your functional components. They're cool because they're lightweight in compare with class components.
First, import useState function from react:
import { useState } from 'react'
Then, before your return, add these lines:
const [name, setName] = useState('');
The first argument here is the name of your state property, and the second one is the function to change it.
So, instead of this:
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
Write this:
handleChange = event => {
setName(event.target.value);
}
If you want to make it more complex, you can rewrite your hook from this:
const [name, setName] = useState('');
to this:
const [state, setState] = useState({
name: '',
checked: false,
});
export default function WorkSection() {
const { register, handleSubmit } = useForm();
const onSubmit = data => {
axios
.get("
...................... my code ...............
and my input form is :
return (
<div className={classes.section}>
<form onSubmit={handleSubmit(onSubmit)}>
<Input
name="Name"
placeholder="Name"
inputRef={register}
fullWidth={true}
/>
<Input
name="email"
type="email"
placeholder="Email"
fullWidth={true}
inputRef={register({ required: true })}
/>
<Input
name="contact"
placeholder="Contact"
fullWidth={true}
inputRef={register({ required: true })}
/>
<Input
name="description"
placeholder="Message"
multiline={true}
fullWidth={true}
inputRef={register({ required: true })}
/>
<button className="btnColor" justify="center" type="submit">
Send Message
</button>
</GridItem>
</GridContainer>
</form>
</div>
Basically i used
inputRef={register}
and other part as satated above.
Right code , worked for me ~

Modal doesnt show up in react

I'm new to react thus the question.
This is my CustomModal,
import React from 'react';
import {useState} from "react";
import {Button, Modal} from "react-bootstrap";
const CustomModal = (props) =>{
const [show, setShow] = useState(true);
const handleClose = () => setShow(false);
return (
<div>
<Modal show={show} animation={false}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>{props.message}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
</div>
)
};
export default CustomModal;
I want to render it inside a class component when user submits a registration form.
class Register extends React.Component {
state = {
email : '',
username: '',
password: '',
second_password: ''
};
handleSubmit = async (event) =>{
event.preventDefault();
const emailValidated = await this.validateEmail(this.state.email);
const usernameValidated = this.validateUsername(this.state.username);
const passwordValidated = this.validatePassword(this.state.password, this.state.second_password);
let registrationComplete = false;
if(emailValidated === true && usernameValidated === true && passwordValidated === true){
registrationComplete = await this.register(this.state.email, this.state.username, this.state.password);
console.log(registrationComplete);
this.showModal("Hello World!"); //This is the function begin called to show the modal.
}
};
validateUsername = (username) =>{
return true;
};
validatePassword = (password, second) =>{
return true;
};
validateEmail = async (email) =>{
return true;
};
//This is the function that should display the modal
showModal = (message) =>{
return (<CustomModal message={message}/>);
};
register = async (email, username, password) =>{
return true;
};
render() {
return (
<div className="register">
<h1>Register</h1>
<Form onSubmit={this.handleSubmit}>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email"
placeholder="Enter email"
value={this.state.email}
onChange={event => this.setState({email: event.target.value})}/>
<Form.Text className="text-muted">
Please make sure you've access to this mail. You'll receive an activation code here.
</Form.Text>
</Form.Group>
<Form.Group controlId="formPlainText">
<Form.Label className="form-label">Username</Form.Label>
<Form.Control type="text"
placeholder="Username"
value={this.state.username}
onChange={event => this.setState({username: event.target.value})}/>
<Form.Text className="text-muted">
Please make it atleast 8 characters long.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
value={this.state.password}
onChange={event => this.setState({password: event.target.value})}/>
<Form.Text className="text-muted">
Please make sure it's atleast 8 characters long and uses a mix of letters and numbers.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Retype Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
value={this.state.second_password}
onChange={event => this.setState({second_password: event.target.value})}/>
</Form.Group>
<Button variant="primary" type="submit">
Register
</Button>
</Form>
</div>
);
}
}
export default Register;
All the values are correct and the console log shows true but the Modal doesn't display. Can someone help me with this?
There are some issues on your code
The customModal has to be part of the render of the Register component
There should be a state to track the status of the modal from the Register component
Also the register has to be notified when the Modal closes
I have modified your code and working. You can find it live here
I prefer attack this problem creating portals here documentation.
you might to have issues with z-index in the future.
Basically, you create an element outside the DOM hierarchy.
Now, your issue is that, you must render modal inside render method and control it, with boolean state "showModal".
I prepare for you an example:
example in my GitHub account
git clone ...
npm install
npm run start
preview:

Add a react-bootstrap alert to handleSubmit in Formik

I'm trying to add a react-bootstrap alert to my Formik form so that the handleSubmit includes an alert to the user that the form has submitted.
I have used the react-bootstrap documented form of Alert, however I had to change the last line because that seems not to work (the error says that I haven't exported anything if I use the react-bootstrap documented form of alert.
My alert is:
import React from 'react';
import {
Alert,
Button,
} from "react-bootstrap";
class AlertDismissible extends React.Component {
constructor(props) {
super(props);
this.state = { show: true };
}
render() {
const handleHide = () => this.setState({ show: false });
const handleShow = () => this.setState({ show: true });
return (
<>
<Alert show={this.state.show} variant="light">
<Alert.Heading>Thanks for your interest </Alert.Heading>
<p>
We'll be in touch with login details shortly.
</p>
<hr />
<div className="d-flex justify-content-end">
<Button onClick={handleHide} variant="outline-success">
Close
</Button>
</div>
</Alert>
{!this.state.show && <Button onClick={handleShow}>Show Alert</Button>}
</>
);
}
}
export default AlertDismissible;
The documentation shows a final line as:
render(<AlertDismissible />);
If I try to use that, an error message saying that render is not defined, and that nothing has been exported appears. So - I replaced that line with my final line.
Then, in my form I have:
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("register")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then => {<AlertDismissible />}
.catch(error => {
console.error("Error adding document: ", error);
});
}
I don't actually know how to get the alert to work (the then statement above is a guess - I can't find any examples. This guess gives an error that says:
Parsing error: Unexpected token, expected ";"
I've tried adding ";" in every place I can think to put one, but it keeps generating errors.
If I try it like this:
.then(<AlertDismissible />)
I get no errors and the form submits, but the alert is not displayed.
Does anyone know how to call a react-bootstrap alert in the handle submit function?
Submit button has:
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}>
Register
</Button>
The onSubmit has:
onSubmit={
this.handleSubmit
}
My entire form looks like this:
import React from 'react';
import { Link } from "react-router-dom";
import { Formik, Form, Field, ErrorMessage, withFormik } from "formik";
import * as Yup from "yup";
import Select from "react-select";
import { fsDB, firebase, settings } from "../../firebase";
import Temporarynav from '../navigation/Temporarynav.jsx';
import Demo from '../landing/Demo.jsx';
import Footer from '../footer/Footer.jsx';
import "./preregister/Form.css";
import AlertDismissible from '../auth/preregister/Alert';
import {
Badge,
Button,
Col,
ComponentClass,
Feedback,
FormControl,
FormGroup,
Table,
Row,
Container
} from "react-bootstrap";
import Alert from 'react-bootstrap/Alert';
const style1 = {
width: "60%",
margin: "auto"
};
const style2 = {
paddingTop: "2em"
};
const style3 = {
marginRight: "2em"
};
const initialValues = {
firstName: "",
lastName: "",
email: "",
role: "",
consent: false,
createdAt: ''
}
class PreregForm extends React.Component {
// constructor(props) {
// super(props);
// // the flag isFormDone will control where you will show the Alert component
// this.state = {
// isFormDone: false
// };
// }
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("preregistrations")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(() => {
// Here is where you flag your form completion and allow the alert to be shown.
// this.setState((prevState) => {...prevState, isFormDone: true});
.catch(error => {
console.error("Error adding document: ", error);
});
}
render() {
const options = [
{ value: "academic", label: "Academic Researcher" },
{ value: "student", label: "Student (inc PhD)" },
]
// const {isFormDone} = this.state;
return(
<Formik
initialValues={initialValues}
validationSchema={Yup.object().shape({
firstName: Yup.string().required("First Name is required"),
lastName: Yup.string().required("Last Name is required"),
email: Yup.string()
.email("Email is invalid")
.required("Email is required"),
role: Yup.string().nullable().required(
"It will help us get started if we know a little about your background"
),
consent: Yup.boolean().oneOf(
[true],
"You must accept the Terms of Use and Privacy Policy"
)
})}
onSubmit={
this.handleSubmit
}
render={({
errors,
status,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
dirty,
values
}) => {
return (
<div>
<Temporarynav />
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<p>
We're almost ready to open this up to the research community. By
registering now, you'll be first in line when the doors open.
</p>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field
name="firstName"
type="text"
className={
"form-control" +
(errors.firstName && touched.firstName ? " is-invalid" : "")
}
/>
<ErrorMessage
name="firstName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field
name="lastName"
type="text"
className={
"form-control" +
(errors.lastName && touched.lastName ? " is-invalid" : "")
}
/>
<ErrorMessage
name="lastName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<Field
name="email"
type="text"
placeholder="Please use your work email address"
className={
"form-control" +
(errors.email && touched.email ? " is-invalid" : "")
}
/>
<ErrorMessage
name="email"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="role">
Which role best describes yours?
</label>
<Select
key={`my_unique_select_keyrole`}
name="role"
className={
"react-select-container" +
(errors.role && touched.role ? " is-invalid" : "")
}
classNamePrefix="react-select"
value={values.role}
onChange={selectedOptions => {
// Setting field value - name of the field and values chosen.
setFieldValue("role", selectedOptions)}
}
onBlur={setFieldTouched}
options={options}
/>
{errors.role && touched.role &&
<ErrorMessage
name="role"
component="div"
className="invalid-feedback d-block"
/>}
</div>
<div className="form-group">
<div className="checkbox-wrapper">
<Field
name="consent"
type="checkbox"
checked={values.consent}
className={
"checkbox" +
(errors.consent && touched.consent ? " is-invalid" : "")
}
/>
<label htmlFor="consent" className="checkbox_label_wrapper">
You must accept the{" "}
<Link className="links" to={"/Terms"}>
Terms of Use
</Link>{" "}
and{" "}
<Link className="links" to={"/Privacy"}>
Privacy Policy
</Link>
</label>
</div>
{errors.consent && touched.consent &&
<ErrorMessage
name="consent"
component="div"
className="invalid-feedback d-block"
/>
}
</div>
<div className="form-group">
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}
>
Register
</Button>
</div>
</Form>
<Demo />
<Footer />
</div>
);
}
}
/>
)
}
}
export default PreregForm;
Next attempt
When I try Julius solution, the alert appears, but as a footer beneath the form - not as a popup alert.
Use state and conditional rendering. Instead of returning a component set state to a variable, in your render use conditional rendering to check if the value is true.
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
};
console.log('formvalues', payload);
fsDB
.collection('register')
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(e => this.setState({ alert: true }))
.catch(error => {
console.error('Error adding document: ', error);
});
};
In your render
render() {
...
return(
....
{this.state.alert && <AlertDismissible />}
...
)
}
Example Demo
Complete form
import React from 'react';
import { Link } from 'react-router-dom';
import { Formik, Form, Field, ErrorMessage, withFormik } from 'formik';
import * as Yup from 'yup';
import Select from 'react-select';
import { fsDB, firebase, settings } from '../../firebase';
import Temporarynav from '../navigation/Temporarynav.jsx';
import Demo from '../landing/Demo.jsx';
import Footer from '../footer/Footer.jsx';
import './preregister/Form.css';
import AlertDismissible from '../auth/preregister/Alert';
import {
Badge,
Button,
Col,
ComponentClass,
Feedback,
FormControl,
FormGroup,
Table,
Row,
Container
} from 'react-bootstrap';
import Alert from 'react-bootstrap/Alert';
const style1 = {
width: '60%',
margin: 'auto'
};
const style2 = {
paddingTop: '2em'
};
const style3 = {
marginRight: '2em'
};
const initialValues = {
firstName: '',
lastName: '',
email: '',
role: '',
consent: false,
createdAt: ''
};
class PreregForm extends React.Component {
constructor(props) {
super(props);
// the flag isFormDone will control where you will show the Alert component
this.state = {
showAlert: false
};
}
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
};
console.log('formvalues', payload);
fsDB
.collection('preregistrations')
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(e => this.setState({ showAlert: true }))
.catch(error => {
console.error('Error adding document: ', error);
});
};
render() {
const options = [
{ value: 'academic', label: 'Academic Researcher' },
{ value: 'student', label: 'Student (inc PhD)' }
];
// const {isFormDone} = this.state;
return (
<div>
{!this.state.showAlert ? (
<div>
<Formik
initialValues={initialValues}
validationSchema={Yup.object().shape({
firstName: Yup.string().required('First Name is required'),
lastName: Yup.string().required('Last Name is required'),
email: Yup.string()
.email('Email is invalid')
.required('Email is required'),
role: Yup.string()
.nullable()
.required(
'It will help us get started if we know a little about your background'
),
consent: Yup.boolean().oneOf(
[true],
'You must accept the Terms of Use and Privacy Policy'
)
})}
onSubmit={this.handleSubmit}
render={({
errors,
status,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
dirty,
values
}) => {
return (
<div>
<Temporarynav />
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<p>
We're almost ready to open this up to the research
community. By registering now, you'll be first in line
when the doors open.
</p>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field
name="firstName"
type="text"
className={
'form-control' +
(errors.firstName && touched.firstName
? ' is-invalid'
: '')
}
/>
<ErrorMessage
name="firstName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field
name="lastName"
type="text"
className={
'form-control' +
(errors.lastName && touched.lastName
? ' is-invalid'
: '')
}
/>
<ErrorMessage
name="lastName"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<Field
name="email"
type="text"
placeholder="Please use your work email address"
className={
'form-control' +
(errors.email && touched.email ? ' is-invalid' : '')
}
/>
<ErrorMessage
name="email"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="role">
Which role best describes yours?
</label>
<Select
key={`my_unique_select_keyrole`}
name="role"
className={
'react-select-container' +
(errors.role && touched.role ? ' is-invalid' : '')
}
classNamePrefix="react-select"
value={values.role}
onChange={selectedOptions => {
// Setting field value - name of the field and values chosen.
setFieldValue('role', selectedOptions);
}}
onBlur={setFieldTouched}
options={options}
/>
{errors.role && touched.role && (
<ErrorMessage
name="role"
component="div"
className="invalid-feedback d-block"
/>
)}
</div>
<div className="form-group">
<div className="checkbox-wrapper">
<Field
name="consent"
type="checkbox"
checked={values.consent}
className={
'checkbox' +
(errors.consent && touched.consent
? ' is-invalid'
: '')
}
/>
<label
htmlFor="consent"
className="checkbox_label_wrapper"
>
You must accept the{' '}
<Link className="links" to={'/Terms'}>
Terms of Use
</Link>{' '}
and{' '}
<Link className="links" to={'/Privacy'}>
Privacy Policy
</Link>
</label>
</div>
{errors.consent && touched.consent && (
<ErrorMessage
name="consent"
component="div"
className="invalid-feedback d-block"
/>
)}
</div>
<div className="form-group">
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}
>
Register
</Button>
</div>
</Form>
<Demo />
<Footer />
</div>
);
}}
/>
</div>
) : (
<AlertDismissible />
)}
</div>
);
}
}
export default PreregForm;
You can't return a component like that within the then function.
You should manage a state flag that shows the alert based on the form completion.
Maybe you could share your whole component where you are handling the submit shown here so we can give you more help (will update the answer if you update the question).
But I think it would be something along the following lines:
class MyFormComponent extends React.Component {
constructor(props) {
super(props);
// the flag isFormDone will control where you will show the Alert component
this.state = {
isFormDone: false
};
}
/** Here your form handling as you posted */
handleSubmit = (formState, { resetForm }) => {
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("register")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(() => {
// Here is where you flag your form completion and allow the alert to be shown.
this.setState((prevState) => ({...prevState, isFormDone: true}));
})
.catch(error => {
console.error("Error adding document: ", error);
});
}
render() {
const {isFormDone} = this.state;
// this will only render the Alert when you complete your form submission
const alert = isFormDone ? <AlertDismissible/> : null;
return(
{/* syntax sugar for React Fragment */}
<>
{/* if it is null, it won't render anything */}
{alert}
{/* Your Form here with your handler */}
{/* ... */}
</>
);
}
}

How to pass input from React Form to Axios get request and display the request result?

I am trying to take input from a user and pass that input into an axios get, when this is done the resultant information is passed into an array that will be displayed as cards.
I am having an issue where the code below is compiling but when enter values into the form fields and press submit, nothing occurrs. Nothing shows up in the web console either.
Where abouts am I going wrong?
const initial_state = {
location: "",
cuisine: "",
searchResults: []
};
class SearchMealForm extends Component {
constructor(props) {
super(props);
this.state = { ...initial_state };
}
//handle user input and inject it into yelp api get request
handleSubmit = event => {
event.preventDefault();
const { location, cuisine, searchResults} = this.state;
this.props.onFormSubmit(this.state(location, cuisine, searchResults));
axios.get(`https://api.yelp.com/v3/businesses/search?location=${location}+IE&categories=${cuisine}`)
.then(response => this.setState({searchResults}))
};
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
//YELP http api get request
searchYelpRestaurants = (location, cuisine, searchResults) => {
axios
.get(
`https://api.yelp.com/v3/businesses/search?location=${location}+IE&categories=${cuisine}`,
{
headers: {
Authorization: `Bearer ${process.env.REACT_APP_API_KEY_YELP}`
}
}
)
.then(res => this.setState({ searchResults: res.data.businesses }));
};
render() {
const { location, cuisine } = this.state;
//create cards with the results from the Yelp API GET
const YelpSearchResults = this.state.searchResults.map(result => {
return (
<div className="ResultCard">
<Card style={{ width: "18rem" }}>
<Card.Img variant="top" src={result.image_url} />
<Card.Body>
<Card.Title>{result.name}</Card.Title>
</Card.Body>
<ListGroup className="list-group-flush">
<ListGroupItem>{result.categories}</ListGroupItem>
<ListGroupItem>{result.rating}</ListGroupItem>
</ListGroup>
<Button variant="primary">Book restaurant</Button>
</Card>
</div>
);
});
// return YelpSearchResults;
// }
return (
<React.Fragment>
<div className="SearchMeal">
<Form onSubmit={this.handleSubmit}>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>City</Form.Label>
<Form.Control
name="location"
type="text"
value={location}
onChange={this.handleChange}
placeholder="location"
/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>Cuisine</Form.Label>
<Form.Control
name="cuisine"
type="text"
value={cuisine}
onChange={this.handleChange}
placeholder="cuisine"
/>
</Form.Group>
</Form.Row>
<Button>Submit</Button>
<Button>Clear</Button>
</Form>
</div>
{YelpSearchResults}
</React.Fragment>
);
}
}
export default SearchMealForm;
here Button type should be specified as submit
<Button type="submit">Submit</Button>
in order for form submit to work!
I would refactor your component to be functional
import React, { useState } from "react";
import ReactDOM from "react-dom";
import axios from "axios";
import {
Col,
Form,
Card,
Button,
ListGroup,
ListGroupItem
} from "react-bootstrap";
const initial_state = {
location: "",
cuisine: "",
searchResults: []
};
const SearchMealForm = ({ onFormSubmit = () => {} }) => {
const [state, setState] = useState(initial_state);
//handle user input and inject it into yelp api get request
const handleSubmit = async event => {
event.preventDefault();
const { location, cuisine } = state;
onFormSubmit(state);
const searchResults = await searchYelpRestaurants({ location, cuisine });
setState({ ...state, searchResults });
};
const handleChange = event => {
setState({
...state,
[event.target.name]: event.target.value
});
};
//YELP http api get request
const searchYelpRestaurants = async ({ location, cuisine }) => {
try {
const { data: { businesses: searchResults } = {} } = await axios.get(
`https://api.yelp.com/v3/businesses/search?location=${location}+IE&categories=${cuisine}`,
{
headers: {
Authorization: `Bearer dBMqyRFmBBg7DMZPK9v3rbGHmrLtlURpNUCJP6gbYHtyHTmboF-Mka-ZkHiDNq-G9ktATohJGD5iKQvelOHg3sDorBDiMgnsaa8SzTH8w6hjGQXlaIexDxFlTW3FXXYx`
}
}
);
return searchResults;
} catch (err) {
console.error(err);
}
return [];
};
const { location, cuisine, searchResults } = state;
//create cards with the results from the Yelp API GET
const YelpSearchResults = searchResults.map(result => (
<div className="ResultCard">
<Card style={{ width: "18rem" }}>
<Card.Img variant="top" src={result.image_url} />
<Card.Body>
<Card.Title>{result.name}</Card.Title>
</Card.Body>
<ListGroup className="list-group-flush">
<ListGroupItem>{result.categories}</ListGroupItem>
<ListGroupItem>{result.rating}</ListGroupItem>
</ListGroup>
<Button variant="primary">Book restaurant</Button>
</Card>
</div>
));
return (
<React.Fragment>
<div className="SearchMeal">
<Form onSubmit={handleSubmit}>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>City</Form.Label>
<Form.Control
name="location"
type="text"
value={location}
onChange={handleChange}
placeholder="location"
/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>Cuisine</Form.Label>
<Form.Control
name="cuisine"
type="text"
value={cuisine}
onChange={handleChange}
placeholder="cuisine"
/>
</Form.Group>
</Form.Row>
<Button type="submit">Submit</Button>
<Button>Clear</Button>
</Form>
</div>
{YelpSearchResults}
</React.Fragment>
);
};
export default SearchMealForm;
<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>

Categories

Resources