I have a friend form that has a button to add friend via ajax call (addNewFriendClick). Once added it should output the id and then using that id the same button (onClickUpdate) should allow to update by grabbing that id.
After adding and clicking a second time to update the friend I get the error below in my console.
The website below should have the /id as the url ending endpoint but i am getting
"[object%20Object]"
PUT https://api.remotebootcamp.dev/api/friends/[object%20Object] 404 (Not Found)
Below is my Routes
<Route path="/friends/*" element={<AddFriend></AddFriend>}>
<Route path=":personId" element={<AddFriend />}></Route>
<Route path="new" element={<AddFriend />}></Route>
</Route>
import React, { useState, useEffect } from "react";
import * as friendService from "../../services/friendService";
import toastr from "toastr";
import { useParams, useNavigate, useLocation } from "react-router-dom";
function AddFriend() {
const [userFormData, setUserFormData] = useState({
title: "",
bio: "",
summary: "",
headline: "",
slug: "",
statusId: "",
primaryImage: "",
});
// useEffect to grab url
const navigate = useNavigate();
const { state } = useLocation();
const friendId = useParams();
const [peepId, setPeepId] = useState(friendId);
console.log({ userFormData, peepId, state }, "param and navigate");
useEffect(() => {
console.log("useEffect firing");
setPeepId(friendId);
if (state) {
setUserFormData((prevState) => {
console.log(state);
return { ...prevState, ...state.payload };
});
}
}, [friendId, state]);
const onFormFieldChange = (event) => {
const target = event.target;
const value = target.value;
console.log("VALUE ->", value);
const name = target.name;
console.log("NAME ->", name);
setUserFormData((prevState) => {
console.log("updater onChange");
const updatedFormData = {
...prevState,
};
updatedFormData[name] = value;
return updatedFormData;
});
};
useEffect(() => {
console.log("useEffect firing");
setPeepId(friendId);
if (state) {
setUserFormData((prevState) => {
console.log(state);
return { ...prevState, ...state.payload };
});
}
}, [friendId, state]);
const addNewFriendClick = (event) => {
event.preventDefault();
console.log(userFormData, "inside addNewFriendClick")
console.log("on Click", { syntheticEvent: event });
friendService.addFriend(userFormData).then(onSuccessAdd).catch(onErrAdd);
};
const onSuccessAdd = (response) => {
console.log(response, "onSuccessAdd response");
// console.log(response.data.item, "onSuccessAdd response.data.item");
setNewFriendInformation(response);
console.log(response,"onSuccessAdd after setNewFriend" )
friendService.getFriendById(response).then(onSuccessGet).catch(onErrorGet);
toastr.success("Congratulations! You have successfully added a friend!");
};
const onErrAdd = (err) => {
console.log("ping err", err);
// swal("Error Registering");
toastr.error(
"Error adding a new friend. Please check if all fields are correct"
);
};
const onClickUpdate = (event) => {
console.log(userFormData, "userFormData inside click Edit");
event.preventDefault();
friendService
.updateFriend(userFormData)
.then(onSuccessUpdate)
.catch(onErrorUpdate);
};
const onSuccessUpdate = (response) => {
console.log(response);
toastr.success("Congratulations! You have successfully updated a friend!");
navigate("/friends");
};
const onErrorUpdate = (error) => {
console.log(error, "inside error update");
toastr.error(
"Error updating friend. Please check all fields are correct and that user being updated is valid"
);
};
const setNewFriendInformation = (id) => {
setUserFormData((prevState) => {
let newState = { ...prevState };
newState.id = id;
return newState;
});
};
const onSuccessGet = (response) => {
console.log(response);
navigate();
};
const onErrorGet = (error) => {
console.log(error);
console.log("inside getById error form");
};
// const updateFriend()
return (
<React.Fragment>
<h1 className="container">Add New</h1>
<hr />
<main role="main">
<div className="container col-6 mt-5 fs-2">
<div className="row">
<div className="col-md-5">
<form>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Title
</label>
<input
type="text"
className="form-control form-control-lg"
id="title"
name="title"
placeholder="Please The Enter Title"
onChange={onFormFieldChange}
value={userFormData.title}
/>
</div>
<div className="mb-3">
<label htmlFor="bio" className="form-label">
Bio
</label>
<input
type="text"
className="form-control form-control-lg"
id="bio"
name="bio"
placeholder="Please Enter The Bio"
value={userFormData.bio}
onChange={onFormFieldChange}
/>
</div>
<div className="mb-3">
<label htmlFor="summary" className="form-label">
Summary
</label>
<input
type="text"
className="form-control form-control-lg"
id="summary"
name="summary"
placeholder="Please Enter The Summary"
onChange={onFormFieldChange}
value={userFormData.summary}
/>
</div>
<div className="mb-3">
<label htmlFor="headline" className="form-label">
Headline
</label>
<input
type="text"
className="form-control form-control-lg"
id="headline"
name="headline"
placeholder="Please Enter The Headline"
onChange={onFormFieldChange}
value={userFormData.headline}
/>
</div>
<div className="mb-3">
<label htmlFor="slug" className="form-label">
Slug
</label>
<input
type="text"
className="form-control form-control-lg"
id="slug"
name="slug"
placeholder="Please The Slug"
onChange={onFormFieldChange}
value={userFormData.slug}
/>
</div>
<div className="mb-3">
<label htmlFor="statusId" className="form-label">
Status Id
</label>
<select
type="select"
className="form-control"
id="statusId"
name="statusId"
placeholder="Please Enter Status ID"
onChange={onFormFieldChange}
value={userFormData.statusId}
>
<option>Default</option>
<option value="Active">Active</option>
<option value="NotSet">NotSet</option>
<option value="Deleted">Deleted</option>
<option value="Flagged">Flagged</option>
</select>
</div>
<div className="mb-3">
<label htmlFor="primaryImage" className="form-label">
Primary Image Url
</label>
<input
type="text"
className="form-control form-control-lg"
id="primaryImage"
name="primaryImage"
placeholder="Please Enter The Primary Image"
onChange={onFormFieldChange}
value={userFormData.primaryImage}
/>
</div>
{userFormData.id ? (
<button
onClick={onClickUpdate}
type="sumbit"
className="btn btn-primary"
>
Update Friend
</button>
) : (
<button
onClick={addNewFriendClick}
type="sumbit"
className="btn btn-primary"
>
Add Friend
</button>
)}
</form>
</div>
</div>
</div>
<div className="col-md-5">
<h5>Output</h5>
<pre>
<code>{JSON.stringify(userFormData, undefined, 2)}</code>
</pre>
</div>
</main>
</React.Fragment>
);
}
export default AddFriend;
import axios from "axios";
import * as helper from "./serviceHelper";
let getFriend = () => {
const config = {
method: "GET",
url: "https://api.remotebootcamp.dev/api/friends?pageIndex=0&pageSize=10",
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config).then(helper.onGlobalSuccess);
//we use data as the param for success handler
};
let addFriend = (payload) => {
const config = {
method: "POST",
url: "https://api.remotebootcamp.dev/api/friends",
data: payload,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config).then(response => {
console.log(response, "inside service addfriend return")
return response.data.item;
});
}
let updateFriend = (id, payload) => {
console.log(id, payload, "from updateFriendservice");
const config = {
method: "PUT",
data: (id, payload),
url: `https://api.remotebootcamp.dev/api/friends/${id}`,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config);
};
let deleteFriend = (id) => {
console.log(id);
const config = {
method: "DELETE",
// data: id,
url: `https://api.remotebootcamp.dev/api/friends/${id}`,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config);
};
let getFriendById = (id, payload) =>{
console.log(id, payload, "inside getFriend friedService")
const config = {
method: "PUT",
data: (id, payload),
url: `https://api.remotebootcamp.dev/api/friends/${id}`,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
}
return axios(config);
}
export { getFriend, addFriend, deleteFriend, updateFriend, getFriendById };
Maybe you should get friendId as following
const { personId: friendId } = useParams();
Also you need to send two prams to friendService.updateFriend() but sent only one param.
Related
After getting member data, member state will be like this.
{
_id: '61d34027ca50827501279eb0',
index: 1,
email: 'bcr90348#zwoho.com',
name: '1',
active: true
}
How to change the values of the above object by changing the text box values?
Ex: Changing the name. Changing email.
import React, { useEffect, useState } from 'react'
import {
CButton,
CCard,
CCardBody,
CCardHeader,
CCol,
CForm,
CFormInput,
CFormLabel,
CRow,
} from '#coreui/react'
import PropTypes from 'prop-types'
const Edit = (props) => {
const id = props.match.params.id
const [member, setMember] = useState({})
const handleLoadMember = async () => {
try {
const _data = await fetch(`http://localhost:4000/api/v1/member/${id}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + localStorage.getItem('token'),
},
})
if (_data.status === 200) {
const data = await _data.json()
setMember(data.member)
} else if (_data.status === 404) {
} else {
throw new Error()
}
} catch (err) {
console.error(err)
}
}
useEffect(() => {
handleLoadMember()
}, [])
return (
<CRow>
<CCol xs={12}>
<CCard className="mb-4 w-75">
<CCardHeader>
<strong>Add New Member</strong>
</CCardHeader>
<CCardBody>
<p className="text-medium-emphasis small">
Click on save button after editing member details.
</p>
<CForm>
<div className="d-inline-flex w-100">
<div className="mb-3 me-1 w-50">
<CFormLabel>Email:</CFormLabel>
<CFormInput
type="email"
placeholder="name#example.com"
value={member.email}
onChange={(e) => console.log(e.target.value)}
/>
</div>
<div className="mb-3 w-50">
<CFormLabel>Name:</CFormLabel>
<CFormInput type="text" placeholder="Perera's Home" value={member.name} />
</div>
</div>
<div className="mb-3">
<CButton color="primary">Submit</CButton>
</div>
</CForm>
</CCardBody>
</CCard>
</CCol>
</CRow>
)
}
Edit.propTypes = {
match: PropTypes.any,
}
export default Edit
Assuming that member already has a value (like you described in your question), you can alter one or multiple properties of it by doing something like this with the spread operator:
setMember(member => ({...member, name: "My New Name", email: "NewEmail"}))
See the Hooks API and useState documentation for more information.
You can define an onChangeHandler like below. And add define name prop to each field.
const onChangeHandler = (e) => {
const { name, value } = e.target;
setMember((prevState) => ({ ...prevState, [name]: value }));
};
<CFormInput
type="email"
placeholder="name#example.com"
name="email"
onChange={onChangeHandler}
value={member.email}
/>
<CFormInput
type="text"
placeholder="Perera's Home"
name="name"
onChange={onChangeHandler}
value={member.name}
/>
Code sandbox
When I connect NEXTJS react-quill, quill does not work.
screen error
I have attached a quill to my site. When I connected Quill the codes were class component. then I switched to arrow function. There was an error while processing
create.js file:
import React, { useState, useRef } from "react";
import dynamic from "next/dynamic";
import axios from "axios";
import Main from "../../layouts/main";
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
import cookie from "react-cookies";
import { withRouter } from "next/router";
import Link from "next/link";
const MyComponent = (props) => {
const [state, setState] = useState({
editorHtml: "",
title: "",
image: {},
message: "",
error_message: "",
error_type: "",
category_id: 1,
token: cookie.load("userToken"),
});
const handleChange = (html) => {
setState({ editorHtml: html });
};
const selectImage = (image) => {
console.log(image);
};
const onSubmitForm = (event) => {
event.preventDefault();
const image = document.querySelector("#image").files[0];
const formData = new FormData();
formData.append("image", image);
formData.append("title", this.state.title);
formData.append("text", this.state.editorHtml);
formData.append("category_id", this.state.category_id);
if (this.state.title.length <= 255) {
axios
.post("http://exapmle.com/api/post/store", formData, {
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "multipart/form-data",
Authorization: "Bearer" + this.state.token,
},
})
.then((res) => {
if (res.data.success == true) {
this.setState({ message: "Blog created!" });
setTimeout(() => {
this.setState({ message: "" });
this.props.router.push("/");
}, 5000);
}
});
}
if (this.state.title.length >= 256) {
this.setState({
error_type: "title",
error_message: "Blog name error!",
});
}
};
const apiPostNewsImage = (data) => {
axios
.post("http://exapmle.com/api/image-upload", data, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => console.log(res));
};
const imageHandler = () => {
const input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
input.click();
input.onchange = async () => {
const file = input.files[0];
const formData = new FormData();
formData.append("image", file);
// Save current cursor state
const range = quill.getSelection(true);
// Insert temporary loading placeholder image
// this.quill.insertEmbed(range.index, "ssurat");
// Move cursor to right side of image (easier to continue typing)
quill.setSelection(range.index + 1);
const res = await axios.post(
"http://exapmle.com/api/image-upload",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
); // API post, returns image location as string e.g. 'http://www.example.com/images/foo.png'
// Remove placeholder image
quill.deleteText(range.index, 1);
// Insert uploaded image
// this.quill.insertEmbed(range.index, 'image', res.body.image);
quill.insertEmbed(range.index, "image", res.data);
};
};
return (
<Main title="Create blog">
<section className="col-12 col-lg-9 shadow bg-white p-3">
{state.token && (
<form
className="row my-4 col-11 col-lg-8 mx-auto"
onSubmit={(event) => onSubmitForm(event)}
>
<h5 className="title col-12 my-3"> Create blog </h5>
{state.message && (
<div className="alert alert-success">{state.message}</div>
)}
<div className="col-12">
<small className="text-danger p-1"></small>
<div className="input-group p-1">
<div className="custom-file">
<input
type="file"
name="image"
id="image"
className="custom-file-input"
onChange={(event) =>
setState({
...state,
image: event.target.files[0],
})
}
id="image"
required
/>
<label
className="custom-file-label"
data-browse="Select"
htmlFor="image"
aria-describedby="image"
>
Image blog
</label>
</div>
</div>
</div>
<div className="col-12 col-lg-6">
<small className="text-danger p-1 col-12"></small>
<div className="form-label-group p-1">
<input
name="title"
type="text"
id="title"
onChange={(event) =>
setState({
...state,
title: event.target.value,
})
}
className={
state.error_type == "title"
? "form-control border border-danger"
: "form-control"
}
// border border-danger
placeholder="Category name"
autoFocus={true}
required
/>
<label htmlFor="title"> Blog name </label>
{state.error_type == "title" && state.error_message && (
<div className="text-danger">{state.error_message}</div>
)}
</div>
</div>
<div className="col-12 col-lg-6 mt-3">
<div className="form-label-group p-1">
<select name="category_id" className="form-control">
<option value="1"> Category</option>
</select>
</div>
</div>
<div className="col-12">
<ReactQuill
ref={(el) => {
quill = el;
}}
onChange={handleChange}
placeholder={props.placeholder}
modules={{
toolbar: {
container: [
[
{ header: "1" },
{ header: "2" },
{ header: [3, 4, 5, 6] },
{ font: [] },
],
[{ size: [] }],
["bold", "italic", "underline", "strike", "blockquote"],
[{ list: "ordered" }, { list: "bullet" }],
["link", "image", "video"],
["clean"],
["code-block"],
],
handlers: {
image: imageHandler,
},
},
}}
/>
</div>
<button className="btn btn-success mx-auto mt-5">
Create blog
</button>
</form>
)}
{!state.token && (
<div className="alert alert-warning d-flex align-items-center d-flex flex-wrap">
this alert
</div>
)}
</section>
</Main>
);
};
export default withRouter(MyComponent);
this not work
ref={(el) => {
quill = el;
}}
When I connect NEXTJS react-quill, quill does not work.
I am able to get the filename of a file under the picture object as seen in the image below
and I make a request to cloudinary with the following, but it says the image path is not correct, which makes sense, but the object I have for the chosen picture does not show the image path.
So how do I get the correct path for cloudinary.
var cloudinary = require("cloudinary").v2;
cloudinary.config({
cloud_name: process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
export default async function signup(req, res) {
console.log(req.body);
const body = req.body;
cloudinary.uploader.upload(
`${body}`,
function (error, result) {
console.log(result, error);
}
);
try {
const result = req.body;
res.status(200).send(result);
} catch (error) {
console.error(error);
res.status(error.requestResult.statusCode).send(error.message);
}
}
Here is what I am sending to the api
const res = await fetch("../api/image", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data.picture[0].name),
});
console.log(res);
I am using react hook forms, and here is the whole code for context
import { useForm, Controller } from "react-hook-form";
import Layout from "../components/Layout";
import ReactDatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { gql, useMutation } from "#apollo/client";
import useSWR from "swr";
import { useRouter } from "next/router";
const CREATE_DECOR_ENTRY = gql`
mutation CreateDecorEntry(
$ownerID: ID!
$description: String!
$pieces: Int!
$purchaser: String!
$alterations: Boolean!
$cost: Int!
$purchaseDate: Date!
$category: String!
) {
createDecor(
data: {
description: $description
pieces: $pieces
purchaser: $purchaser
alterations: $alterations
cost: $cost
purchaseDate: $purchaseDate
category: $category
owner: { connect: $ownerID }
}
) {
description
}
}
`;
const fetcher = (url) => fetch(url).then((r) => r.json());
const fetchWithImage = (url, image) =>
fetch(`${url}?image=${image}`).then((r) => r.json());
export default function Decor() {
const { data: user, error: userError } = useSWR("/api/user", fetcher);
const { data: cookieData, error: cookieError } = useSWR(
"/api/cookie",
fetcher
);
var cookieBearer = `Bearer ${cookieData}`;
return (
<Layout>
<h1>Enter your Decor Data</h1>
{user && cookieBearer && <Form user={user} cookieBearer={cookieBearer} />}
</Layout>
);
}
const Form = ({ cookieBearer, user }) => {
const Router = useRouter();
const [
createDecorEntry,
{ data: createDecorEntryData, loading: saving },
] = useMutation(CREATE_DECOR_ENTRY, {
context: {
headers: {
authorization: cookieBearer,
},
},
});
const { register, handleSubmit, errors, control } = useForm();
const onSubmit = async (data) => {
console.log(data);
let yourDate = data.purchaseDate;
const offset = yourDate.getTimezoneOffset();
yourDate = new Date(yourDate.getTime() - offset * 60 * 1000);
const date = yourDate.toISOString().split("T")[0];
console.log(date);
const dataMassage = {
...data,
pieces: parseInt(data.pieces),
cost: parseInt(data.cost),
purchaseDate: date,
};
console.log(dataMassage);
const res = await fetch("../api/image", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data.picture[0].name),
});
console.log(res);
// const res = await createDecorEntry({
// variables: {
// ownerID: user.id,
// ...dataMassage,
// },
// }).catch(console.error);
// Router.push(`/decor/data`);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<h2>Image</h2>
<input ref={register} type="file" name="picture" />
</div>
<div>
<h2>Description</h2>
<input
type="text"
placeholder="Description"
name="description"
ref={register({ required: true })}
/>
</div>
<div>
<h2>Number of Pieces</h2>
<input
type="number"
placeholder="Number of Pieces"
name="pieces"
ref={register({ required: true })}
/>
</div>
<div>
<h2>Purchaser</h2>
<input
type="text"
placeholder="Purchaser"
name="purchaser"
ref={register({ required: true })}
/>
</div>
<div>
<h2>Alternations Needed</h2>
<input
type="checkbox"
placeholder="Alternations Needed"
name="alterations"
ref={register({ required: true })}
/>
</div>
<div>
<h2>Cost</h2>
<input
type="number"
placeholder="Cost"
name="cost"
ref={register({ required: true })}
/>
</div>
<div>
<h2>Purchase Date</h2>
<Controller
name="purchaseDate"
control={control}
render={({ onChange, value }) => (
<ReactDatePicker selected={value} onChange={onChange} />
)}
/>
</div>
<div>
<h2>Category</h2>
<select name="category" ref={register}>
<option value="Curation">Curation</option>
<option value=" Good"> Good</option>
</select>
</div>
<div>
<input type="submit" />
</div>
</form>
);
};
According to documentation, you can't just upload file. You will have to either save it somewhere first (for example locally on disk), or convert it into base64.
Interestingly enough, other part of documentation suggests that you an send an array buffer, but I'm not sure if it is available in Node
I am only posting this answer so others can benefit, I ended up going the array buffer route.
import formidable from "formidable";
const cloudinary = require("cloudinary").v2;
const fs = require("fs");
const path = require("path");
let streamifier = require('streamifier');
cloudinary.config({
cloud_name: process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
// first we need to disable the default body parser
export const config = {
api: {
bodyParser: false,
},
};
export default async function image(req, res) {
try {
const form = new formidable.IncomingForm();
form.uploadDir = "./";
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
console.log(JSON.stringify(files));
console.log(files.image.path);
var oldPath = files.image.path;
var rawData = fs.readFileSync(oldPath);
console.log(rawData);
let cld_upload_stream = cloudinary.uploader.upload_stream(
{
folder: "sick-fits"
},
function(error, result) {
console.log(error, result);
res.status(200).send({ result });
}
);
streamifier.createReadStream(rawData).pipe(cld_upload_stream);
});
} catch (error) {
console.error(error);
res.status(error.requestResult.statusCode).send(error.message);
}
}
I have an issue mapping over a passing prop, from the parent component (App.js) to the child component (Label.js). the terminal showing me a success compiling with a warning. when I just click the login button in my application, I directly got an alert that says: "Cannot read property 'map' of undefined" and after clicking ok, this error is showing: "TypeError: Cannot read property 'map' of undefined is showing when I'm trying to map over the props passed from parent component to child component". I'm new to React hooks, Any help is much appreciated, and excuse the long lines of code.
Thank you
App.js
import Label from "./Label";
import Register from "./Registration";
export default function App() {
const [add_task_data, setAddTaskData] = useState({
title: "",
description: "",
date: "",
priority: "",
});
const [state, setState] = useState({
isAuthenticated: false,
});
const [login, setLogin] = useState({
email: "",
password: "",
});
const [todos, setTodos] = useState([]);
const fetchTodos = () => {
if (state.isAuthenticated) {
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append(
"Authorization",
`Bearer ${localStorage.getItem("access_token")}`
);
var requestOptions = {
method: "GET",
headers: myHeaders,
redirect: "follow",
};
fetch("https://codeminos-todo.tk/api/v1/to-dos", requestOptions)
.then((response) => response.text())
.then((json) => {
const result = JSON.parse(json);
setTodos(result.data);
})
.catch((error) => console.log("error", error));
}
};
// const checkUserAuth = () => {
if (state.isAuthenticated) {
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append(
"Authorization",
`Bearer ${localStorage.getItem("access_token")}`
);
var requestOptions = {
method: "GET",
headers: myHeaders,
redirect: "follow",
};
fetch("https://codeminos-todo.tk/api/v1/labels", requestOptions)
.then((response) => response.text())
.then((json) => {
setState({
isAuthenticated: true,
});
})
.catch((error) => {
setState({
isAuthenticated: false,
});
});
}
function handleChange(key, value) {
setAddTaskData({
...add_task_data,
[key]: value,
});
}
function hanldeLoginChange(key, value) {
setLogin({
...login,
[key]: value,
});
}
const handleLoginSubmit = (event) => {
event.preventDefault();
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("email", "pas2ss#gmail.com2");
urlencoded.append("password", "212312322");
var requestOptions = {
method: "POST",
headers: myHeaders,
body: urlencoded,
};
fetch("https://codeminos-todo.tk/api/login",requestOptions)
.then((response) => {
return response.json();
})
.then((data) => {
if (data.access_token !== undefined) {
localStorage.setItem("access_token", data.access_token);
setState({
...state,
isAuthenticated: true,
});
}
})
.catch((error) => {
alert(error.message);
});
};
const handleAddToDoSubmit = (event) => {
event.preventDefault();
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append(
"Authorization",
`Bearer ${localStorage.getItem("access_token")}`
);
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("title", add_task_data.title);
urlencoded.append("description", add_task_data.description);
urlencoded.append("priority", add_task_data.priority);
urlencoded.append("date", add_task_data.date);
var requestOptions = {
method: "POST",
headers: myHeaders,
body: urlencoded,
redirect: "follow",
};
fetch("https://codeminos-todo.tk/api/v1/to-dos", requestOptions)
.then((response) => response.text())
.then((result) => {
fetchTodos();
})
.catch((error) => console.log("error", error));
};
return (
<>
<div>
<Register /> <br/>
<br/>
</div>
<div className="App">
<h2>Welcome to your task manager app</h2>
{!state.isAuthenticated && (
<div>
<h2>You are not authenticated, please login</h2>
<form onSubmit={(event) => handleLoginSubmit(event)}>
<div>
<label>Email: </label>
<input
type="text"
name="email"
onChange={(event) => {
hanldeLoginChange("email", event.target.value);
}}
/>
</div>
<div>
<label>password</label>
<input
type="text"
name="password"
onChange={(event) => {
hanldeLoginChange("password", event.target.value);
}}
/>
</div>
<input type="submit" value="login" />
</form>
</div>
)}
{state.isAuthenticated && (
<div>
<h2>Tasks</h2>
{todos.map((todo) => {
return (
<div>
Title {todo.title} --- description: {todo.description}
</div>
);
})}
<button
onClick={() => {
setState({
...state,
isAuthenticated: false,
});
localStorage.removeItem("access_token");
}}
>
Logout
</button>
<h2>Add TODO</h2>
<form
onSubmit={(event) => {
handleAddToDoSubmit(event);
}}
>
<div>
<label>Title</label>
<input
type="text"
name="title"
onChange={(event) => {
handleChange("title", event.target.value);
}}
/>
</div>
<div>
<label>description</label>
<input
type="text"
name="description"
onChange={(event) => {
handleChange("description", event.target.value);
}}
/>
</div>
<div>
<label>date</label>
<input
type="text"
name="date"
onChange={(event) => {
handleChange("date", event.target.value);
}}
/>
</div>
<div>
<label>priority</label>
<input
type="text"
name="priority"
onChange={(event) => {
handleChange("priority", event.target.value);
}}
/>
</div>
<Label {...add_task_data.title}/>
<input type="submit" value="add todo" />
</form>
{JSON.stringify(add_task_data)}
</div>
)}
</div>
</>
);
}
Label.js
export default function Label(props){
const [labels, setLabels] = useState({ label: "" });
const [state, setState] = useState({
isAuthenticated: false,
});
function handleChangeLabel(key, value) {
setLabels({
...labels,
[key]: value,
});
}
if (state.isAuthenticated) {
const handleSubmitLabel = (event) => {
event.preventDefault();
var myHeaders = new Headers();
myHeaders.append(
"Authorization",
`Bearer ${localStorage.getItem("access_token")}`
);
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("name", labels.label);
var requestOptions = {
method: "POST",
headers: myHeaders,
body: urlencoded,
redirect: "follow",
};
fetch("https://codeminos-todo.tk/api/v1/labels", requestOptions)
.then((response) => response.text())
.then((json) => {
const result = JSON.parse(json);
setLabels(result.data);
setState({
isAuthenticated: true,
});
})
.catch((error) => {
setState({
isAuthenticated: false,
});
});
};
}
return (
<>
<form onSubmit={(event) => {handleSubmitLabel(event)}}>
<span>
<label>Add a Label to your task</label>
{props.add_task_data.map(task => {
<select onChange={handleChangeLabel} name="task-label">
<option>{task}</option>
</select>
})}
</span>
</form>
</>
);
}
The issue is that you are expecting, in Label.js, the prop add_task_data when you try to access it:
export default function Label(props){
// ...
return (
// ...
// will throw when "add_task_data" prop value is *undefined*
{props.add_task_data.map(task => {
// ...
})}
// ...
);
}
Then, in App.js, when you instantiate the component:
<Label {...add_task_data.title}/>
you are not passing the add_task_data expected prop.
In this case, you are deconstructing the spread of add_task_data.title which is a string, which doesn't seem to be making sense for your current scenario.
A solution to your issue, which I believe is what you were intending to do, would be just instantiating Label as:
<Label {...add_task_data}/>
In parent when you are passing data to child, you are passing
<Label {...add_task_data.title}/> which means you are passing only title but in child class you are trying to map whole data which you don't have.
so instead pass whole of the dataset like <Label {add_task_data}/>.
index.js
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import { ToastContainer, toast } from 'react-toastify';
import { useHistory } from 'react-router-dom';
import 'react-toastify/dist/ReactToastify.css';
const AddRequest = () => {
const [request, setRequest] = useState({
product_name: '',
description: '',
product_img: '',
});
const [error, setError] = useState({
product_error: ''
})
const handleChange = e => {
e.preventDefault();
const {name, value} = e.target;
let formError = {...error};
switch(name) {
case "product_error":
formError.product_error =
value.length < 0 ? "Required" : "";
break;
default:
break;
}
setError({formError, [name]: value});
console.log(error)
setRequest({ ...request, [e.target.name]: e.target.value });
};
const headers = {
'x-access-token': localStorage.getItem('accessToken'),
'content-type': 'multipart/form-data'
}
const handleImageChange = async e => {
e.preventDefault();
setRequest({ ...request, [e.target.name]: e.target.files });
};
const handleSubmit = async e => {
e.preventDefault();
const formData = new FormData()
for (const file of request.product_img) {
formData.append('product_img', file)
}
formData.append('product_name', request.product_name)
formData.append('description', request.description)
await Axios.post(config.api, formData, {
headers: headers
})
.then(res => {
toast.success('Added Successfully!', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
.catch(e => {
console.log(e)
toast.error('not Added', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
setTimeout(function () {
history.push('/')
}, 1500);
};
return (
<>
<ToastContainer />
<form onSubmit={e => handleSubmit(e)} noValidate>
<div className="form-group">
<label htmlFor='product_name'>Product Name:</label>
<input type="text" name="product_name" id="product_name" placeholder="Enter Product Name" className="form-control" noValidate onChange={e => handleChange(e)} />
{errors.product_error}
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='description'>Description:</label>
<input type="text" name="description" id="description" placeholder="Description" className="form-control" onChange={e => handleChange(e)} />
</div>
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='product_img'>Product Image:</label> <br />
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} />
</div>
<button type="submit" className="btn btn-success"> Add Request Rekko </button>
</form>
</>
)
};
export default AddRequest
Everything is working fine but form validation is not working. I am new to react and tried many things but still, it is not working. Can anyone help me with form validation? I only want all 3 fields to be required. It shows the message that this field is required if someone submits a form without entering anything.
You can simply add the tag required inside the input, like this:
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} required />