Hi everyone so I am making an application for hosting events and when I try to add and event the submit button doesn't do anything. Please help me.
THIS IS THE HANDLE SUBMIT FUNCTION
handleSubmit = e => {
e.preventDefault();
const errors = this.validate();
this.setState({ errors: errors || {} });
if (errors) return;
this.doSubmit();
};
THIS IS THE BUTTON
renderButton(label) {
return (
<button disabled={this.validate()} className="btn btn-primary">
{label}
</button>
);
}
THIS IS THE THE EVENTFORM
import React from "react";
import Form from "./form";
import Joi from "joi-browser";
import { getEvent, saveEvent } from "../services/fakeEvents";
import { getCategories } from "../services/fakeCategories";
class EventForm extends Form {
state = {
data: {
title: "",
eventPicture: "",
categoryId: "",
eventTime: "",
numberOfAtendies: "",
location: "",
details: ""
},
categories: [],
errors: {}
};
schema = {
_id: Joi.string(),
title: Joi.string()
.required()
.label("Event Title"),
categoryId: Joi.string()
.required()
.label("Choose Category"),
eventTime: Joi.number()
.required()
.label("Choose Event Time"),
numberOfAtendies: Joi.number()
.required()
.min(1)
.max(100000)
.label("Numeber of Attendies"),
location: Joi.string()
.required()
.label("Event Location"),
details: Joi.string()
.required()
.label("Event Details")
.min(250)
.max(300)
};
componentDidMount() {
const categories = getCategories();
this.setState({ categories });
const eventId = this.props.match.params.id;
if (eventId === undefined) return;
const event = getEvent(eventId);
if (!event) return this.props.history.replace("/not-found");
this.setState({ data: this.mapToViewModel(event) });
}
mapToViewModel(event) {
return {
_id: event._id,
title: event.title,
categoryId: event.category._id,
eventTime: event.eventTime,
numberOfAtendies: event.numberOfAtendies,
location: event.location,
details: event.details
};
}
doSubmit = () => {
saveEvent(this.state.data);
this.props.history.push("/home");
console.log(this.state)
};
render() {
return (
<div>
<h1>Create Event</h1>
<form onSubmit={this.handleSubmit}>
{this.renderInput("title", "Title")}
{this.renderSelect("categoryId", "Category", this.state.categories)}
{this.renderInput("eventTime", "Event Time")}
{this.renderInput("numberOfAtendies", "Number of Attendies")}
{this.renderInput("location", "Location")}
{this.renderInput("details", "Details")}
{this.renderButton("Create")}
</form>
</div>
);
}
}
export default EventForm;
Not sure if this makes sense I'm new to this so please let me know if further information is needed.
Your problem is here, it should be something like this :
renderButton(label) {
return (
<button disabled={this.validate() ? true : false} className="btn btn-primary">
{label}
</button>
);
}
Related
I am building a simple login form page in React. The <form> has 2 inputs (email and password), an error message, and a submit button.
The submit button can be set to the Loading state during the authentication request.
So I have the following component:
function LoginForm() {
const [state, setState] = useState({ loading: false, error: "", x: 1 }); // x value only for visualising...
const auth = useAuth();
const navigate = useNavigate();
const login = async ({ email, password }) => {
try {
if (!email || !password) {
return { errors: "Invalid fields" };
}
const { errors } = await auth.authenticate(email, password);
if (!errors) {
return {};
}
console.log("LoginButton", "Error login. Not Redirecting", errors);
return {
errors: "Por favor verifique seu email e/ou senha e tente novamente.",
};
} catch (error) {
return { errors: "Unexpected error. Please, try again later." };
}
};
const inputs = [
{
name: "email",
},
{
name: "password",
type: "password",
},
];
const handleSubmit = (values) => {
setState({ ...state, loading: true, error: "", x: 2 }); // First call
login(values).then(({ errors: error }) => {
if (!error) navigate("/profile");
const newState = { loading: false, error: "Error while login", x: 3 }; // Second call
setState(newState);
});
};
useEffect(() => {
console.log(state); // Only for debugin
});
return (
<Form
inputs={inputs}
onSubmit={handleSubmit}
>
<ErrorMessage text={state.error} />
<div>
<Submit loading={state.loading}>Entrar</Submit>
<Link
to="/forgot-password"
>
Esqueceu sua senha?
</Link>
</div>
</Form>
);
}
The <Form/> component only gets the inputs array and creates the list of inputs...
The login function was called, and it set the state successfully on the first setState call (x: 2), but on the second call, the state was reset to the default value (x: 1).
Why did the second setState reset the default value? How can I fix this?
I think I've solved... But I don't Understand how...
function LoginForm() {
const [state, setState] = useState({ loading: false, error: "", x: 1 });
const auth = useAuth();
const navigate = useNavigate();
const inputs = [
{
name: "email",
},
{
name: "password",
type: "password",
},
];
const handleSubmit = async (values) => {
const { email, password } = values;
setState({ ...state, loading: true, error: "", x: 2 });
auth.authenticate(email, password).then(({ errors }) => {
if (!errors) navigate("/profile");
const newState = { loading: false, error: errors, x: 3 };
setState(newState);
});
};
useEffect(() => {
console.log(state);
});
return (
<Form
inputs={inputs}
onSubmit={handleSubmit}
>
<ErrorMessage text={state.error} />
<div>
<Submit loading={state.loading}>Entrar</Submit>
<Link
css={`
color: white;
`}
to="/forgot-password"
>
Esqueceu sua senha?
</Link>
</div>
</Form>
);
}
export default LoginForm;
This worked...
I'm strugling with my form in typescript react. Basicly I created 2 simple components Button and Input and add them to the another component Form where I created a whole form.
After submit I should get something like this:
telephone: "323423234"
email: "tress#wess.com"
message: "weklfnwlkf"
name: "less"
surname: "mess"
But after submit I get weird response like this:
"": "323423234"
email: "tress#wess.com"
message: "weklfnwlkf"
name: "less"
surname: "mess"
telephone: ""
It is a little bit werido because I done something like this couple days ago and now idk what to do.
There is sample of my Form code
const Form = () => {
interface FormDataType {
telephone: string;
name: string;
surname: string;
email: string;
message: string;
}
const formData: FormDataType = {
telephone: '',
name: '',
surname: '',
email: '',
message: '',
};
const [responseBody, setResponseBody] = useState<FormDataType>(formData);
const clearState = () => {
setResponseBody({ ...formData });
};
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
setResponseBody({ ...responseBody, [name]: value });
};
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(responseBody);
clearState();
};
return (
<>
<form onSubmit={handleSubmit}>
{FormData.map((option) => (
<Input
key={option.name}
label={option.label}
type={option.type}
className={option.className}
name={option.name}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
handleChange(e)
}
/>
))}
<div className='div'>
<Button
type='submit'
title={'Simple test'}
className={'btn-primary'}
/>
</div>
</form>
</>
);
};
export default Form;
And when I'm invoking in handleSubmit function clearState() it doesn't refresh states in webpage inputs.
I hope this is what it needs, I made some changes, but you can adapt it to your project
export default function App() {
interface FormDataType {
telephone: string;
name: string;
surname: string;
email: string;
message: string;
}
const formData: FormDataType = {
telephone: "",
name: "",
surname: "",
email: "",
message: ""
};
const [values, setValues] = useState<FormDataType | any>(formData);
// reset
const reset = (newFormState = formData) => {
setValues(newFormState);
};
// handleInputChange
const handleInputChange = ({ target }: any) => {
setValues({ ...values, [target.name]: target.value });
};
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(values);
reset();
};
const data = [
{
type: "text",
name: "name"
},
{
type: "text",
name: "surname"
},
{
type: "email",
name: "email"
},
{
type: "tel",
name: "telephone"
},
{
type: "text",
name: "message"
}
];
return (
<>
<form onSubmit={handleSubmit}>
{data.map((option) => (
<input
key={option.name}
value={values[option.name]}
type={option.type}
name={option.name}
placeholder={option.name}
onChange={handleInputChange}
/>
))}
<div className="div">
<button type="submit">Simple test</button>
</div>
</form>
</>
);
}
Your reset doesn't work because your inputs are uncontrolled.
To have them reset properly, you should make them controlled by passing them a value prop. It would look something like this:
<Input
key={option.name}
label={option.label}
type={option.type}
className={option.className}
name={option.name}
value={responseBody[option.name]} // Add this
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
handleChange(e)
}
/>
This will connect the responseBody form data with the input values.
As to the odd console logged value, it would appear that at least one of the option.name values is empty/undefined (looks like the telephone object). Verify that the FormData contains complete and correct values.
I'm using the newest vue#3.1.2 with Composition API. I want to use current vee-validate#4.4.5 accordingly to their documentation. But when handleSubmit is used nothing works as I expect.
<form #submit="onSubmit">
<div class="mb-3">
<label for="edit-email" class="form-label">E-mail</label>
<input
id="edit-email"
name="email"
class="form-control"
v-model="email"
type="text"
/>
<div class="invalid-feedback">{{ emailError }}</div>
</div>
<button class="btn btn-primary" type="submit">Save</button>
</form>
import { useField, useForm } from "vee-validate";
import { object, string } from "yup";
export default {
name: "App",
setup() {
const { handleSubmit } = useForm();
const onSubmit = handleSubmit((values) => {
console.log(values, submitCount.value); // values is empty: {}
});
const schema = object({
email: string().required().email(),
});
useForm({
validationSchema: schema,
initialValues: {
email: "",
},
});
const { value: email, errorMessage: emailError } = useField("email");
return {
email,
emailError,
onSubmit,
};
},
};
Reproduced problem:
💡 https://codesandbox.io/s/vue3-vee-validate-handlesubmit-with-no-values-oj0ot?file=/src/App.vue
Documentation:
https://vee-validate.logaretm.com/v4/guide/composition-api/handling-forms#javascript-submissions-ajax
And I have two problems:
Why submit doesn't invoke validate() for the form and as result doesn't prevent submit when they're mistakes?
Why in the handleForm callback argument values is empty?
What am I doing wrong?
I think your first example does not work because you are using useForm twice and you have to use it once
I've tested this code on your example and it worked for me
let response = ref("Empty.");
const schema = object({
email: string().required().email(),
password: string().required().min(4),
});
const { errors: formErrors, handleSubmit, setFieldError, submitCount } = useForm({
validationSchema: schema,
initialValues: {
email: "",
password: "",
},
// validateOnMount: true,
});
i am working on a project and creating a form to create tours. everything is working fine just the issue is form input values are exchanging
for ex -
actual output- { tourName: 'pune darshan', location: '999', price: 'pune' }
expected output :- { tourName: 'pune darshan', location: 'pune', price: '999' }
i dont know where i am going wrong i am stuck here since 6 hrs
here is what i have tried
form component
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { createTour } from "../../store/slices/tourSlice";
import "./createListing.scss";
const CreateListing = () => {
const [tour, setTour] = useState({
tourName: "",
price: "",
location: "",
});
const dispatch = useDispatch();
const handleInput = (event) => {
setTour((tour) => ({
...tour,
[event.target.name]: event.target.value,
}));
};
const handleSubmit = (event) => {
event.preventDefault();
dispatch(createTour(tour.tourName, tour.price, tour.location));
};
return (
<div>
<div className='form-controller'>
<form action='' method='post' onSubmit={handleSubmit}>
<div className='form-group'>
<input
type='text'
className='form-control'
name='tourName'
placeholder='Enter Tour Name'
onChange={handleInput}
required
/>
</div>
<div className='form-group'>
<input
type='text'
className='form-control'
name='location'
placeholder='Enter Tour Location'
onChange={handleInput}
required
/>
</div>
<div className='form-group'>
<input
type='number'
className='form-control'
name='price'
placeholder='Enter Tour Cost'
onChange={handleInput}
required
/>
</div>
<div className='text-center'>
<button type='submit theme-btn'>Create Tour</button>
</div>
</form>
</div>
</div>
);
};
export default CreateListing;
here is the redux toolkit file
import { createSlice } from "#reduxjs/toolkit";
import axios from "axios";
import { history } from "./../../helpers/history";
export const initialState = {
tourName: "",
location: "",
price: "",
error: "",
loading: false,
};
const tourSlice = createSlice({
name: "tour",
initialState,
reducers: {
tourCreateRequest: (State, action) => {
return {
loading: true,
};
},
tourCreateSuccess: (state, action) => {
return { loading: false, tourInfo: action.payload };
},
tourCreateFail: (state, action) => {
return {
loading: false,
error: action.payload,
};
},
},
});
const {
tourCreateFail,
tourCreateRequest,
tourCreateSuccess,
} = tourSlice.actions;
export default tourSlice.reducer;
export const createTour = (tourName, location, price) => async (dispatch) => {
try {
dispatch(tourCreateRequest);
const tourData = {
tourName,
location,
price,
};
const res = await axios.post(
"http://localhost:3000/api/v1/tours",
tourData
);
if (res) {
dispatch(tourCreateSuccess);
// history.push("/dashboard");
} else {
dispatch(
tourCreateFail(
error.response && error.response.data.message
? error.response.data.message
: error.message
)
);
console.log("error");
}
} catch (error) {
dispatch(
tourCreateFail(
error.response && error.response.data.message
? error.response.data.message
: error.message
)
);
}
};
here is the model file
const mongoose = require("mongoose");
const tourSchema = mongoose.Schema(
{
tourName: { type: String },
rating: { type: String, default: 4.5 },
location: { type: String },
price: { type: String, default: 999 },
},
{ timestamps: {} }
);
const Tour = mongoose.model("Tour", tourSchema);
module.exports = Tour;
here is controller code
const createTours = async (req, res, next) => {
const { tourName, price, location } = req.body;
console.log(req.body);
try {
const newTour = new Tour({
tourName,
price,
location,
});
newTour.save();
res.status(200).json({
status: "success",
newTour,
});
} catch (error) {
res.status(404).json({
status: "failed",
error: error,
});
}
};
You pass the parameters in the createTour function in the wrong order.
You should update the dispatch line:
dispatch(createTour(tour.tourName, tour.location, tour.price));
I am trying to set state via this.setState() of username and password when user types a value in username and password field. I am using onChange event type
ISSUE: the state is not changing. I log this.state.data.username in the render().
import React, { Component } from "react";
import { Form, Button } from "react-bootstrap";
import { Link } from "react-router-dom";
var Joi = require("joi-browser");
class Login extends Component {
state = {
data: { username: "a", password: "b " },
errors: {
email: "ddsfds",
password: "aaaa"
}
};
schema = {
username: Joi.string()
.min(0)
.required()
.label("Username"),
password: Joi.string()
.required()
.label("Password")
};
handleSubmit = event => {
event.preventDefault();
console.log("submited.", event.target);
const { data } = this.state;
const { err } = Joi.validate(data, this.schema);
if (err) {
console.log("error is true", err);
} else {
console.log("not true");
}
};
handleEmailOnChange = event => {
const inputUsername = event.target.value;
console.log("input is...", inputUsername);
this.setState({ username: inputUsername });
};
handlePassword = event => {
const passwordInput = event.target.value;
this.setState({ password: passwordInput });
};
render() {
console.log("username ", this.state.data.username);
return (
<div id="form-wrapper">
<Form>
<Form.Group controlId="formBasicEmail">
<h4>Sign In</h4>
<Form.Control
type="email"
placeholder="Enter email"
onChange={this.handleEmailOnChange}
/>
{/* <span>{this.state.errors.username} </span> */}
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Control
type="password"
placeholder="Password"
onChange={this.handlePassword}
/>
</Form.Group>
<div id="register-wrapper">
<Link to="/register" type="button" className="btn btn-warning">
Register Account
</Link>
<Button
variant="primary"
className="m-2"
type="submit"
onClick={this.handleSubmit}
>
Submit
</Button>
</div>
</Form>
</div>
);
}
}
export default Login;
You aren't updating the state correctly or not using it correctly. The state in your constructor has data object with username and password
handleEmailOnChange = event => {
const inputUsername = event.target.value;
console.log("input is...", inputUsername);
this.setState(prev => ({data: {...prev.data, username: inputUsername } }));
};
handlePassword = event => {
const passwordInput = event.target.value;
this.setState(prev => ({data: {...prev.data, password: passwordInput } }));
};
The state you are changing is this.state.username, the one you console is this.state.data.username.
To set data in your state, use:
this.setState(prevState => ({
data: {
username: inputUsername,
...prevState.data
}
})