I'm trying to set form validation in React-bootstrap.
I've just written code in accordance with React-bootstrap document.
https://react-bootstrap.netlify.app/components/forms/#forms-validation
I confirmed validation is activated and data is changed when I push submit button.
But only setTimeout method is not working because of adding React-bootstrap validation code.
I couldn't find where I missed and should fix.
Could you tell me the differences between my code and document.
Also, I add comments to my code to make clearly.
PS: I debugged my code. I found that that code was skipped.
I am investigating causes now.
.then(response => {
if (response.data != null) {
alert('編集完了!')
window.setTimeout(() => {
history.push("/")
}, 1000)
}
})
Before adding code
import axios from 'axios'
import { useEffect, useState } from 'react'
import { Card, Form, Button, Col } from 'react-bootstrap';
import React, { Component } from 'react'
import { BrowserRouter, Route, Link, useHistory } from 'react-router-dom'
import Box from '#material-ui/core/Box';
import { Copyright } from './Copyright';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faList, faHome, faClipboardCheck } from '#fortawesome/free-solid-svg-icons'
export const EditData = (props) => {
const history = useHistory()
const id = props.listNo;
const [dataOne, setDataOne] = useState({});
useEffect(() => {
axios.get("http://localhost:8080/action/edit/" + id).then((response) =>
setDataOne(response.data)
)
}, [])
const handleChange = event => {
setDataOne({ ...dataOne, [event.target.name]: event.target.value });
};
const handleSubmit = event => {
event.preventDefault();
const list = {
listNo: dataOne.listNo,
softwareName: dataOne.softwareName,
saiyouDate: dataOne.saiyouDate,
version: dataOne.version,
shubetu: dataOne.shubetu,
licenseManage: dataOne.licenseManage,
youto: dataOne.youto,
bikou: dataOne.bikou,
authorizer: dataOne.authorizer,
approvalDate: dataOne.approvalDate,
url: dataOne.url
}
axios.post("http://localhost:8080/action/edit/contents", list)
.then(response => {
if (response.data != null) {
alert('編集完了!')
window.setTimeout(() => {
history.push("/")
}, 1000)
}
})
};
return (
<div>
<div className="container">
<Card>
<Card.Header className="text-center" style={{ backgroundColor: '#75A9FF', color: '#FFF' }}>
<FontAwesomeIcon icon={faList} />使用許可ソフトウェアリスト
</Card.Header>
<Form id="listFormId" onSubmit={handleSubmit}>
<Form.Control
required
type="hidden"
name="listNo"
value={dataOne.listNo || ""}
onChange={handleChange}
/>
<Card.Body>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>ソフトウェア名</Form.Label>
<Form.Control
type="text"
name="softwareName"
value={dataOne.softwareName || ""}
onChange={handleChange}
/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>採用日</Form.Label>
<Form.Control
type="text"
name="saiyouDate"
value={dataOne.saiyouDate || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>バージョン</Form.Label>
<Form.Control
type="text"
name="version"
value={dataOne.version || ""}
onChange={handleChange}
/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>種別</Form.Label>
<Form.Control
type="text"
name="shubetu"
value={dataOne.shubetu || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>ライセンス</Form.Label>
<Form.Control
type="text"
name="licenseManage"
value={dataOne.licenseManage || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>用途</Form.Label>
<Form.Control
type="text"
name="youto"
value={dataOne.youto || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>備考</Form.Label>
<Form.Control
type="text"
name="bikou"
value={dataOne.bikou || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>承認者</Form.Label>
<Form.Control
type="text"
name="authorizer"
value={dataOne.authorizer || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>承認日</Form.Label>
<Form.Control
type="text"
name="approvalDate"
value={dataOne.approvalDate || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>URL</Form.Label>
<Form.Control
type="text"
name="url"
value={dataOne.url || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
</Card.Body>
<Card.Footer style={{ "textAlign": "right" }}>
<Link to="/">
<Button size="sm" variant="outline-primary" type="button">
<FontAwesomeIcon icon={faHome} />トップ
</Button>
</Link>
<Button size="sm" variant="outline-success" type="submit" style={{ marginLeft: '10px' }} >
<FontAwesomeIcon icon={faClipboardCheck} /> 編集完了
</Button>
</Card.Footer>
</Form>
</Card>
</div>
<Box pt={4} pb={4}>
<Copyright />
</Box>
</div>
)
}
Add react-bootstrap validation
import axios from 'axios'
import { useEffect, useState } from 'react'
import { Card, Form, Button, Col } from 'react-bootstrap';
import React, { Component } from 'react'
import { BrowserRouter, Route, Link, useHistory } from 'react-router-dom'
import Box from '#material-ui/core/Box';
import { Copyright } from './Copyright';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faList, faHome, faClipboardCheck } from '#fortawesome/free-solid-svg-icons'
export const EditData = (props) => {
const [validated, setValidated] = useState(false);//Add
const history = useHistory()
const id = props.listNo;
const [dataOne, setDataOne] = useState({});
useEffect(() => {
axios.get("http://localhost:8080/action/edit/" + id).then((response) =>
setDataOne(response.data)
)
}, [])
const handleChange = event => {
setDataOne({ ...dataOne, [event.target.name]: event.target.value });
};
const handleSubmit = event => {
//Add and Change code
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
setValidated(true);
} else {
const list = {
listNo: dataOne.listNo,
softwareName: dataOne.softwareName,
saiyouDate: dataOne.saiyouDate,
version: dataOne.version,
shubetu: dataOne.shubetu,
licenseManage: dataOne.licenseManage,
youto: dataOne.youto,
bikou: dataOne.bikou,
authorizer: dataOne.authorizer,
approvalDate: dataOne.approvalDate,
url: dataOne.url
}
axios.post("http://localhost:8080/action/edit/contents", list)
.then(response => {
if (response.data != null) {
alert('編集完了!')
window.setTimeout(() => {
history.push("/")
}, 1000)
}
})
}
};
return (
<div>
<div className="container">
<Card>
<Card.Header className="text-center" style={{ backgroundColor: '#75A9FF', color: '#FFF' }}>
<FontAwesomeIcon icon={faList} />使用許可ソフトウェアリスト
</Card.Header>
{// add novalidate and required
}
<Form id="listFormId" noValidate validated={validated} onSubmit={handleSubmit}>
<Form.Control
required
type="hidden"
name="listNo"
value={dataOne.listNo || ""}
onChange={handleChange}
/>
<Card.Body>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>ソフトウェア名</Form.Label>
<Form.Control
required
type="text"
name="softwareName"
value={dataOne.softwareName || ""}
onChange={handleChange}
/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>採用日</Form.Label>
<Form.Control
required
type="text"
name="saiyouDate"
value={dataOne.saiyouDate || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>バージョン</Form.Label>
<Form.Control
required
type="text"
name="version"
value={dataOne.version || ""}
onChange={handleChange}
/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>種別</Form.Label>
<Form.Control
required
type="text"
name="shubetu"
value={dataOne.shubetu || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>ライセンス</Form.Label>
<Form.Control
required
type="text"
name="licenseManage"
value={dataOne.licenseManage || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>用途</Form.Label>
<Form.Control
required
type="text"
name="youto"
value={dataOne.youto || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>備考</Form.Label>
<Form.Control
type="text"
name="bikou"
value={dataOne.bikou || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>承認者</Form.Label>
<Form.Control
required
type="text"
name="authorizer"
value={dataOne.authorizer || ""}
onChange={handleChange} />
</Form.Group>
<Form.Group as={Col}>
<Form.Label>承認日</Form.Label>
<Form.Control
required
type="text"
name="approvalDate"
value={dataOne.approvalDate || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>URL</Form.Label>
<Form.Control
required
type="text"
name="url"
value={dataOne.url || ""}
onChange={handleChange} />
</Form.Group>
</Form.Row>
</Card.Body>
<Card.Footer style={{ "textAlign": "right" }}>
<Link to="/">
<Button size="sm" variant="outline-primary" type="button">
<FontAwesomeIcon icon={faHome} />トップ
</Button>
</Link>
<Button size="sm" variant="outline-success" type="submit" style={{ marginLeft: '10px' }} >
<FontAwesomeIcon icon={faClipboardCheck} /> 編集完了
</Button>
</Card.Footer>
</Form>
</Card>
</div>
<Box pt={4} pb={4}>
<Copyright />
</Box>
</div>
)
}
I resolved that Error in the following way.
I wrote event.preventDefault(); outside if statement like that.
event.preventDefault();
//Add and Change code
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.stopPropagation();
setValidated(true);
} else {
Related
I am creating a form using react-bootstrap, react-hook-form, and yup for validation.
I have several fields that are not required like url and radio.
I have used a custom regex instead of yup's url() as it is really strict, for example not accepting google.com or www.google.com.
Also, there are radio type fields like offerInternships, offerVisaSponsorships, offerRemoteWorking which I have declared as notRequired in yup's schema.
The problem is when I press submit button, errors are shown indicating that they must be filled, and I only be able to proceed if I filled them with correct values.
I am not really sure what could have gone wrong here.
Edit 1: I have modified the regex to accept empty strings by adding |^$ at the end of re, and the url now can accept empty strings and act as if it's not required (I am not sure if this actually fixes the problem), but the radio type's problem still exists.
import { Container, Row, Col, Button, Form } from "react-bootstrap";
import * as yup from "yup";
import { useForm } from "react-hook-form";
import { yupResolver } from "#hookform/resolvers/yup";
/**
* Company's validation schema.
*/
const re =
/^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm;
const formSchema = yup.object().shape({
url: yup.string().matches(re, "Enter a valid URL!").required(),
name: yup.string().required(),
location: yup.object().shape({
country: yup.string().required(),
state: yup.string().required(),
city: yup.string().required(),
address: yup.string().required(),
}),
offerInternships: yup.bool().default(false).notRequired(),
offerRemoteWork: yup.bool().default(false).notRequired(),
offerVisaSponsorship: yup.bool().default(false).notRequired(),
socialMedia: yup.object().shape({
Linkedin: yup.string().matches(re, "Enter a valid URL!").notRequired(),
GitHub: yup.string().matches(re, "Enter a valid URL!").notRequired(),
}),
});
const RequestForm = () => {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm({
resolver: yupResolver(formSchema),
mode: "all",
});
/**
* Handling the submittion of the form
*/
const onSubmit = async (data) => {
try {
console.log(errors);
console.log(data);
} catch (error) {
console.log(error);
}
};
return (
<>
<Container id="RequestForm-UserForm" className="mt-5 outer-border p-5">
<Form onSubmit={handleSubmit(onSubmit)}>
<Row id="company-details-row">
<Col id="company-details-row-input" sm={12} md={9}>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>Company's name</Form.Label>
<Form.Control
type="text"
placeholder="e.g. Microsoft"
{...register("name")}
isInvalid={!!errors?.name}
/>
</Form.Group>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>Company's website</Form.Label>
<Form.Control
type="text"
placeholder="e.g. https://www.microsoft.com"
{...register("url")}
isInvalid={!!errors.url}
/>
</Form.Group>
<h3 className="mb-0">Location</h3>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>Country</Form.Label>
<Form.Control
type="text"
placeholder="e.g. Egypt, United States of America,...etc."
{...register("location.country")}
isInvalid={!!errors.location?.country}
/>
</Form.Group>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>State/Governorate</Form.Label>
<Form.Control
type="text"
placeholder="e.g. Cairo, California, Berlin...etc."
{...register("location.state")}
isInvalid={!!errors.location?.state}
/>
</Form.Group>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>City</Form.Label>
<Form.Control
type="text"
placeholder="e.g. Maadi, San Francisco,...etc."
{...register("location.city")}
isInvalid={!!errors.location?.city}
/>
</Form.Group>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>Address</Form.Label>
<Form.Control
type="text"
placeholder="e.g. 14th Zaki Sayed St."
{...register("location.address")}
isInvalid={!!errors.location?.address}
/>
</Form.Group>
<h3 className="mt-2 mb-0">Social Media</h3>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>
<i className="icon ion-social-linkedin"></i> Linkedin
</Form.Label>
<Form.Control
type="text"
placeholder="e.g. https://www.linkedin.com/company/x"
{...register("socialMedia.Linkedin")}
isInvalid={!!errors.socialMedia?.Linkedin}
/>
</Form.Group>
<Form.Group className="mb-2" controlId="formBasicEmail">
<Form.Label>
<i className="icon ion-social-github"></i> GitHub
</Form.Label>
<Form.Control
type="text"
placeholder="e.g. https://www.github.com/company"
{...register("socialMedia.GitHub")}
isInvalid={!!errors.socialMedia?.GitHub}
/>
</Form.Group>
<h3 className="mt-2 mb-0">Culture & Environment</h3>
<div id="offer-Internship" key={"inline-radio-internships"}>
<Form.Label>Does your company offer internships? 🎓</Form.Label>
<br></br>
<Form.Check
inline
label="Yes"
value={"true"}
{...register("offerInternships", { required: false })}
type={"radio"}
isInvalid={!!errors.offerInternships}
/>
<Form.Check
inline
label="No"
value={"false"}
{...register("offerInternships", { required: false })}
type={"radio"}
isInvalid={!!errors.offerInternships}
/>
</div>
<div id="offer-VisaSponsorship" key={"inline-radio-visa"}>
<Form.Label>
Does your company offer visa sponsorship? ✈️
</Form.Label>
<br></br>
<Form.Check
inline
label="Yes"
value={"true"}
{...register("offerVisaSponsorship", { required: false })}
type={"radio"}
isInvalid={!!errors.offerVisaSponsorship}
/>
<Form.Check
{...register("offerVisaSponsorship", { required: false })}
inline
label="No"
value={"false"}
type={"radio"}
isInvalid={!!errors.offerVisaSponsorship}
/>
</div>
<div id="offer-remoteWork" key={"inline-radio-remote"}>
<Form.Label>
Does your company offer remote working? 🗺️
</Form.Label>
<br></br>
<Form.Check
{...register("offerRemoteWork", { required: false })}
inline
label="Yes"
value={"true"}
type={"radio"}
isInvalid={!!errors.offerRemoteWork}
/>
<Form.Check
{...register("offerRemoteWork", { required: false })}
inline
label="No"
value={"false"}
type={"radio"}
isInvalid={!!errors.offerRemoteWork}
/>
</div>
</Col>
</Row>
<Row id="company-submit text-center">
<Col className={"text-center"} sm={12}>
<h2 className="fs-1 main-color-1-dark">
We have reached to the end of the form! 🎆
</h2>
<Button variant="success" type="submit" className="rubik-font">
Submit form
</Button>
</Col>
</Row>
</Form>
</Container>
</>
);
};
export default RequestForm;
So, this is my App.js file and the next picture is what I get when I hit submit. I want to get all the entered values to be printed on console but that's not happening.
I am also using Flask as backend and I want to get all these data into app.py so how to do that ?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
petalLen: "",
petalWid: "",
sepalLen: "",
sepalWid: "",
};
this.handleOnChange = this.handleOnChange.bind(this);
}
handleOnChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const data = new FormData(event);
for (let [key, value] of data.entries()) {
console.log(key, value);
}
}
render() {
return (
<div className="App">
<h1>Deploy Models for Humans </h1>
<Form>
<Container>
<Row className="Rr">
<Col>
<Form.Label>Petal Length</Form.Label>
<Form.Control
type="text"
name="petalLen"
value={this.state.petalLen}
onChange={this.handleOnChange}
placeholder="Petal Length"
/>
</Col>
<Col>
<Form.Group>
<Form.Label>Petal Width</Form.Label>
<Form.Control
type="text"
name="petalWid"
value={this.state.petalWid}
onChange={this.handleOnChange}
placeholder="Petal Width"
/>
</Form.Group>
</Col>
<Col>
<Form.Group>
<Form.Label>Sepal Length</Form.Label>
<Form.Control
type="text"
name="sepalLen"
value={this.state.sepalLen}
onChange={this.handleOnChange}
placeholder="Sepal Length"
/>
</Form.Group>
</Col>
<Col>
<Form.Group>
<Form.Label>Sepal Width</Form.Label>
<Form.Control
type="text"
name="sepalWid"
value={this.state.sepalWid}
onChange={this.handleOnChange}
placeholder="Sepal Width"
/>
</Form.Group>
</Col>
</Row>
<Button variant="primary" type="submit" onClick={this.handleSubmit}>
Submit
</Button>
</Container>
</Form>
</div>
);
}
}
After I hit submit :
I have a multistep form for signing up. What is the easiest and the best approach for form validation? What should I use? Is it alright to use Formik for that? Could you suggest to me what to do?
Here is one of the forms:
return(
<Container>
<Row className="justify-content-center">
<Col md="8">
<Card border="dark">
<Card.Title className="text-center">New User</Card.Title>
<Card.Body>
<Form>
<Form.Group controlId="formGridFirstName">
<Form.Label>First Name</Form.Label>
<Form.Control type="text" value={formValues.firstName} onChange={handleChange('firstName')} />
</Form.Group>
<Form.Group controlID="formGridLastName">
<Form.Label>Last Name</Form.Label>
<Form.Control type="text" value={formValues.lastName} onChange={handleChange('lastName')} />
</Form.Group>
<Form.Group controlID="formGridEmail">
<Form.Label>Email</Form.Label>
<Form.Control type="email" value={formValues.email} onChange={handleChange('email')} />
</Form.Group>
<Form.Group controlId="formGridPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" value={formValues.password} onChange={handleChange('password')} />
</Form.Group>
<Form.Group controlId="formGridPhone">
<Form.Label>Phone</Form.Label>
<Form.Control type="tel" value={formValues.phone} onChange={handleChange('phone')} />
</Form.Group>
<Button variant="light" type="submit" size="lg" onClick={redirectToHome}>Cancel</Button>
<Button variant="primary" type="submit" size="lg" onClick={saveAndContinue}>Next</Button>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
);
};
You can use Formik and a Yup for validation schema:
https://formik.org/docs/api/formik#validationschema-schema----schema
npm links:
https://www.npmjs.com/package/formik
https://www.npmjs.com/package/yup
It will look like this:
export default function MyForm() {
const initValues = {
firstName: "",
lastName: "",
email: "",
password: "",
phone: ""
};
const schema = Yup.object().shape({
firstName: Yup.string(),
lastName: Yup.string(),
email: Yup.string().email("Email format is invalid."),
password: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/[a-zA-Z]/, "Password can only contain Latin letters."),
phone: Yup.string().phone(" ")
});
return (
<Formik validationSchema={schema} initialValues={initValues}>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
setFieldTouched
} = props;
return (
<Container>
<Row className="justify-content-center">
<Col md="8">
<Card border="dark">
<Card.Title className="text-center">New User</Card.Title>
<Card.Body>
<Form>
<Form.Group controlId="formGridFirstName">
<Form.Label>First Name</Form.Label>
<Form.Control
name="firstName"
type="text"
value={values.firstName}
onChange={handleChange}
setFieldTouched={setFieldTouched}
errors={errors}
/>
</Form.Group>
<Form.Group controlID="formGridLastName">
<Form.Label>Last Name</Form.Label>
<Form.Control
name="lastName"
type="text"
value={values.lastName}
onChange={handleChange}
setFieldTouched={setFieldTouched}
errors={errors}
/>
</Form.Group>
<Form.Group controlID="formGridEmail">
<Form.Label>Email</Form.Label>
<Form.Control
name="email"
type="email"
value={values.email}
onChange={handleChange}
setFieldTouched={setFieldTouched}
errors={errors}
/>
</Form.Group>
<Form.Group controlId="formGridPassword">
<Form.Label>Password</Form.Label>
<Form.Control
name="password"
type="password"
value={values.password}
onChange={handleChange}
setFieldTouched={setFieldTouched}
errors={errors}
/>
</Form.Group>
<Form.Group controlId="formGridPhone">
<Form.Label>Phone</Form.Label>
<Form.Control
name="phone"
type="tel"
value={values.phone}
onChange={handleChange}
setFieldTouched={setFieldTouched}
errors={errors}
/>
</Form.Group>
<Button
variant="light"
type="submit"
size="lg"
onClick={redirectToHome}
>
Cancel
</Button>
<Button
variant="primary"
type="submit"
size="lg"
onClick={saveAndContinue}
>
Next
</Button>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
);
}}
</Formik>
);
}
But you should change also your Form.Control component:
Add
import { ErrorMessage, getIn } from "formik";
const error = getIn(props.errors, props.name);
and add to your Input these attributes
onChange={(e) => {setFieldTouched("firstName");handleChange(e);}
error={error}
and Error to show
<Error component="div" name={props.name} />
I would suggest adding your own validators and bundling inputs that are of the same type. For example First Name and Last Name are both strings so you can have a validator for string types. You could do it like this
//validator.js
const stringValidator = (value) => {
if(isEmpty(value)){
return { isValid: false, errors: ["Field cannot be blank"] }
}
return { isValid: true, errors: [] }
}
const config = {
firstName: stringValidator,
lastName: stringValidator,
email: emailValidator,
cellphone: cellphoneValidator,
password: passwordValidator
}
const getValidator = (questionId) => config[questionId];
export default (questionId, value) => {
const validate = getValidator(questionId);
return validate(value)
}
...
// Form.js class
answerQuestion(questionId){
return (e) => {
const answer = e.target.value;
const validation = validate(questionId, answer)
const { errors } = validation;
let { fields } = this.state;
fields[questionId] = { errors, value, label: field.label }
this.setState({ fields })
}
}
...
<Form>
{this.state.fields.map( field => {
return(
<Form.Group>
<Form.Label>{field.label}</Form.Label>
<Form.Control type="text" value={field.value} onChange={this.answerQuestion(field.questionId)} />
{field.errors.map(err => <span>{err}</span>}
</Form.Group>
)
}
</Form>
I'm trying to get the currently logged in users email and use it in my fetch() call. I can currently get the email from getfirstapi() and use it in my form but I'm having trouble passing it into my getSecondApi() where the fetch() is ?
Iv tried creating a getEmail function to return it, but with no luck.
Code
import * as React from "react";
import axios from "axios";
import { Form, Card, Grid } from "tabler-react";
import { Button, Modal } from "semantic-ui-react";
import Auth from '#aws-amplify/auth';
import '../../index.css';
import { arrayOf } from "prop-types";
//const config = require('../config.json');
class GeneralInformation extends React.Component {
constructor(props) {
super(props);
this.state = {
// States from API
firstname: "",
middlename: "",
surname: "",
city: "",
postcode: "",
state: "",
email: "",
about: "",
// States for editable form
formfirstname: "",
formmiddlename: "",
formsurname: "",
formcity: "",
formpostcode: "",
formstate: "",
formabout: "",
// Modal State
open: false,
};
}
getUseremail() {
return Auth.currentAuthenticatedUser().then(user => user.attributes.email)
}
email = Auth.currentAuthenticatedUser().then(user => user.attributes.email)
getFirstApi() {
return Auth.currentAuthenticatedUser().then((user) => {
this.setState({email: user.attributes.email, formemail: user.attributes.email})
});
}
getSecondApi(email) {
fetch(`https://ezha2ns0bl.execute-api.ap-southeast-2.amazonaws.com/prod/userdata?foo=${encodeURIComponent(email)}`)
.then(res => res.json())
.then(
console.log("THIS IS RESULT2 " + email),
(result) => {
this.setState({
firstname: result.Item.userFirstName,
middlename: result.Item.userMiddleName,
surname: result.Item.userLastName,
city: result.Item.userCity,
postcode: result.Item.userPostcode,
state: result.Item.userState,
about: result.Item.userAbout,
formfirstname: result.Item.userFirstName,
formmiddlename: result.Item.userMiddleName,
formsurname: result.Item.userLastName,
formcity: result.Item.userCity,
formpostcode: result.postcode,
formstate: result.Item.userState,
formabout: result.Item.userAbout,
});
console.log("THIS IS RESULT1 " + result)} ,
)
}
componentDidMount() {
this.getFirstApi();
this.getSecondApi();
}
handleChange = (input) => (event) => {
this.setState({ [input]: event.target.value });
};
handleSubmit = async (event) => {
event.preventDefault();
this.setState((prevState) => ({
// If submitting new values, update the state to represent the new data
firstname: prevState.formfirstname,
middlename: prevState.formmiddlename,
surname: prevState.formsurname,
city: prevState.formcity,
postcode: prevState.formpostcode,
email: prevState.formemail,
userState: prevState.formstate,
about: prevState.formabout,
open: false,
}))
try {
const params = {
"userFirstName": this.state.formfirstname,
"userMiddleName": this.state.formmiddlename,
"userLastName": this.state.formsurname,
"userCity": this.state.formcity,
"userPostCode": this.state.formpostcode,
"userEmail": this.state.formemail,
"userState": this.state.formstate,
"userAbout": this.state.formabout,
"userType": "jobseeker"
};
await axios.post('https://qrg3idkox4.execute-api.ap-southeast-2.amazonaws.com/prod/{userEmail}/', params);
}catch (err) {
console.log(`An error has occurred: ${err}`);
}
};
cancelForm = () => {
// If cancelling, reset any fields that have been changed to the original values so that when the modal is re-opened, the old values are shown
this.setState((prevState) => ({
formfirstname: prevState.firstname,
formmiddlename: prevState.middlename,
formsurname: prevState.surname,
formcity: prevState.city,
formpostcode: prevState.postcode,
formstate: prevState.state,
formabout: prevState.about,
open: false,
}));
};
openModal = () => {
this.setState({ open: true });
};
render() {
const {
firstname,
middlename,
surname,
city,
postcode,
state,
email,
about,
formfirstname,
formmiddlename,
formsurname,
formcity,
formpostcode,
formstate,
formabout,
open,
} = this.state;
return (
<div className="card" name="generalInfo">
<Card.Body>
<Grid>
<Grid.Row>
<Grid.Col md={7}>
<Card.Title>General Information</Card.Title>
</Grid.Col>
<Grid.Col md={5}>
{/* MODAL BUTTON */}
<Button
floated="right"
basic
icon="pencil"
type="button"
compact
onClick={this.openModal}
/>
</Grid.Col>
</Grid.Row>
<Grid.Row>
{/* ROW 1 */}
<Grid.Col md={4}>
<Form.Group label="First Name">
<Form.Input name="firstname" readOnly value={firstname} />
</Form.Group>
</Grid.Col>
<Grid.Col md={4}>
<Form.Group label="Middle Name">
<Form.Input name="middlename" readOnly value={middlename} />
</Form.Group>
</Grid.Col>
<Grid.Col md={4}>
<Form.Group label="Surname">
<Form.Input name="surname" readOnly value={surname} />
</Form.Group>
</Grid.Col>
{/* ROW 2 */}
<Grid.Col md={3}>
<Form.Group label="City">
<Form.Input name="city" readOnly value={city} />
</Form.Group>
</Grid.Col>
<Grid.Col md={2}>
<Form.Group label="Post Code">
<Form.Input name="postcode" readOnly value={postcode} />
</Form.Group>
</Grid.Col>
<Grid.Col md={3}>
<Form.Group label="State">
<Form.Input name="state" readOnly value={state} />
</Form.Group>
</Grid.Col>
<Grid.Col md={4}>
<Form.Group label="Email">
<Form.Input name="email" readOnly value={email} />
</Form.Group>
</Grid.Col>
{/* ROW 3 */}
<Grid.Col md={12}>
<Form.Group className="mb=0" label="About Me">
<Form.Textarea
name="aboutme"
rows={3}
disabled
readOnly
value={about}
/>
</Form.Group>
</Grid.Col>
</Grid.Row>
</Grid>
</Card.Body>
{/* MODAL CONTENT */}
<Modal
style={{ position: "relative" }}
closeOnDimmerClick={false}
open={open}
>
<Modal.Header>Edit Info</Modal.Header>
<Modal.Content>
<Form onSubmit={this.handleSubmit}>
<Grid.Row>
<Grid.Col md={4}>
<Form.Group label="First Name">
<Form.Input
name="firstname"
value={formfirstname}
onChange={this.handleChange("formfirstname")}
/>
</Form.Group>
</Grid.Col>
<Grid.Col md={4}>
<Form.Group label="Middle Name">
<Form.Input
name="middlename"
value={formmiddlename}
onChange={this.handleChange("formmiddlename")}
/>
</Form.Group>
</Grid.Col>
<Grid.Col md={4}>
<Form.Group label="Surname">
<Form.Input
name="surname"
value={formsurname}
onChange={this.handleChange("formsurname")}
/>
</Form.Group>
</Grid.Col>
</Grid.Row>
{/* ROW 2 */}
<Grid.Row>
<Grid.Col md={3}>
<Form.Group label="City">
<Form.Input
name="city"
value={formcity}
onChange={this.handleChange("formcity")}
/>
</Form.Group>
</Grid.Col>
<Grid.Col md={2}>
<Form.Group label="Post Code">
<Form.Input
name="postcode"
value={formpostcode}
onChange={this.handleChange("formpostcode")}
/>
</Form.Group>
</Grid.Col>
<Grid.Col md={3}>
<Form.Group label="State">
<Form.Input
name="state"
value={formstate}
onChange={this.handleChange("formstate")}
/>
</Form.Group>
</Grid.Col>
</Grid.Row>
{/* ROW 3 */}
<Grid.Row>
<Grid.Col md={12}>
<Form.Group className="mb=0" label="About Me">
<Form.Textarea
name="aboutme"
rows={3}
value={formabout}
onChange={this.handleChange("formabout")}
/>
</Form.Group>
</Grid.Col>
</Grid.Row>
{/* ROW 4 - SUBMIT */}
<Grid.Row>
<Grid.Col md={12}>
<Button
floated="left"
basic
type="button"
color="red"
onClick={this.cancelForm}
>
{" "}
Cancel{" "}
</Button>
<Button floated="right" basic type="submit" color="green">
{" "}
Accept Changes{" "}
</Button>
</Grid.Col>
</Grid.Row>
</Form>
</Modal.Content>
</Modal>
</div>
);
}
}
export default GeneralInformation;
Form
EDIT
> getEmailApi() { return
> Auth.currentAuthenticatedUser().then((user) => {
> const { attributes = {} } = user;
> console.log(attributes['email']);
> })}
iv created this function to get the email
but don't know how to pass it into the getSecondApi
My Solution
getEmailApi() {
return Auth.currentAuthenticatedUser().then((user) => {
const { attributes = {} } = user;
console.log(attributes['email']);
let email = attributes['email']
return email
})}
getFirstApi() {
return Auth.currentAuthenticatedUser().then((user) => {
this.setState({email: user.attributes.email, formemail: user.attributes.email})
});
}
getSecondApi(email) {
fetch(`https://ezha2ns0bl.execute-api.ap-southeast-2.amazonaws.com/prod/userdata?userEmail=${encodeURIComponent(email)}`)
.then(res => res.json())
.then(
console.log("THIS IS RESULT2 " + email),
(result) => {
this.setState({
firstname: result.Item.userFirstName,
middlename: result.Item.userMiddleName,
surname: result.Item.userLastName,
city: result.Item.userCity,
postcode: result.Item.userPostcode,
state: result.Item.userState,
about: result.Item.userAbout,
formfirstname: result.Item.userFirstName,
formmiddlename: result.Item.userMiddleName,
formsurname: result.Item.userLastName,
formcity: result.Item.userCity,
formpostcode: result.postcode,
formstate: result.Item.userState,
formabout: result.Item.userAbout,
});
console.log("THIS IS RESULT1 " + result)} ,
)
}
BeforDidMount() {
this.getEmailApi().then(email => this.getSecondApi(email)); }
componentDidMount() {
this.BeforDidMount();
this.getFirstApi();
}
So this may be something simple but I'm hitting a roadblock. I want to take in a form input but can't seem to figure out how to append the value correctly so its appending string is captured.
I'm using Formik with yup in react.
<InputGroup>
<Field
id="appended-input"
name="domain_url"
type="text"
value={values.domain_url}
className={
"form-control" +
(errors.domain_url && touched.domain_url
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="domain_url"
component="div"
className="invalid-feedback"
/>
<InputGroupAddon addonType="append">
.localhost
</InputGroupAddon>
</InputGroup>
Any help would be appreciated. I just want to get the .localhost to be automatically added to the input items. for this field. I thought I could do something like value=({values.domain_url} + ".localhost") but that didn't seem to work and as you may already tell I am very new to javascript.
Thank you!
Full code below, I'm also having issues with datepicker displaying within the formik state, and then there's how to even get the values to push to my getTenant(function) to be passed to my api.
static propTypes = {
addTenant: PropTypes.func.isRequired,
};
onSubmit = (values) => {
values.preventDefault();
this.props.addTenant(values);
};
render() {
const {
domain_url,
schema_name,
name,
config,
} = this.state;
const TenantSchema = Yup.object().shape({
domain_url: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client URL header is required"),
schema_name: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client db name is required"),
name: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client name is required"),
});
return (
<div className={s.root}>
<Formik
initialValues={{
domain_url: "",
schema_name: "",
client_name: "",
config: [
{
date: "",
Tenant_description: "",
},
],
}}
// validationSchema={TenantSchema} this is commented off because it breaks
submittions
onSubmit={(values, { setSubmitting, resetForm }) => {
setSubmitting(true);
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
resetForm();
setSubmitting(false);
}, 100);
}}
//onSubmit={onSubmit}
>
{({
values,
errors,
status,
touched,
handleBlur,
handleChange,
isSubmitting,
setFieldValue,
handleSubmit,
props,
}) => (
<FormGroup>
<Form onSubmit={handleSubmit}>
<legend>
<strong>Create</strong> Tenant
</legend>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Show URL
</Label>
<Col md={7}>
<InputGroup>
<Field
id="appended-input"
name="domain_url"
type="text"
value={values.domain_url}
onSubmit={(values) => {
values.domain_url = values.domain_url + ".localhost";
}} //this isn't working
className={
"form-control" +
(errors.domain_url && touched.domain_url
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="domain_url"
component="div"
className="invalid-feedback"
/>
<InputGroupAddon addonType="append">
.localhost
</InputGroupAddon>
</InputGroup>
</Col>
</FormGroup>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Database Name
</Label>
<Col md={7}>
<Field
name="schema_name"
type="text"
className={
"form-control" +
(errors.schema_name && touched.schema_name
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="schema_name"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Name
</Label>
<Col md={7}>
<Field
name="name"
type="text"
className={
"form-control" +
(errors.name && touched.name
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="name"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FieldArray
name="config"
render={(arrayHelpers) => (
<div>
{values.config.map((config, index) => (
<div key={index}>
<FormGroup row>
<Label
md={4}
className="text-md-right"
for="mask-date"
>
Tenant Description
</Label>
<Col md={7}>
<TextareaAutosize
rows={3}
name={`config.${index}.tenant_description`}
id="elastic-textarea"
type="text"
onReset={values.event_description}
placeholder="Quick description of tenant"
onChange={handleChange}
value={values.tenant_description}
onBlur={handleBlur}
className={
`form-control ${s.autogrow} transition-height` +
(errors.tenant_description &&
touched.tenant_description
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="tenant_description"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FormGroup row>
<Label
for="normal-field"
md={4}
className="text-md-right"
>
Date
</Label>
<Col md={7}>
<DatePicker
tag={Field}
name={`config.${index}.date`}
type="date"
selected={values.date}
value={values.date}
className={
"form-control" +
(errors.date&& touched.date
? " is-invalid"
: "")
}
onChange={(e) =>
setFieldValue("date", e)
}
/>
<ErrorMessage
name="date"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
</div>
))}
</div>
)}
/>
<div className="form-group">
<button
type="submit"
disabled={isSubmitting}
className="btn btn-primary mr-2"
>
Save Tenant
</button>
<button type="reset" className="btn btn-secondary">
Reset
</button>
</div>
</Form>
<Col md={7}>{JSON.stringify(values)}</Col>
</FormGroup>
)}
</Formik>
</div>
);
}
}
export default connect(null, { addTenant })(TenantForm);
You could use setFieldValue if you want to customize the value
https://jaredpalmer.com/formik/docs/api/formik#setfieldvalue-field-string-value-any-shouldvalidate-boolean--void
You can add onChange
<Field
id="appended-input"
name="domain_url"
type="text"
value={values.domain_url}
onChange={st => {
let value = st.target.value;
let suffix = ".localhost";
let index = value.indexOf(".localhost");
if (index > 0) {
suffix = "";
}
//add suffix 'localhost' if it is not already added
props.setFieldValue("domain_url", value + suffix);
}}
className={
"form-control" +
(errors.domain_url && touched.domain_url ? " is-invalid" : "")
}
/>;
But adding suffix is more preferable on onSubmit:
onSubmit = {(values, actions) => {
console.log('valuesbefore',values)
values.domain_url= values.domain_url+ ".localhost"
console.log('valuesafter',values)
this.props.addTenant(values);
};