Show added posts without refreshing page in React - node.js

I have been working on a personal project outside university, developing a blog.
Right now I'm trying to implement a "home page" where after a succesfull login, the user can post text, and right after that it appears under the Create post div you can see in the pic
This is what I have managed to accomplish so far:
This is the home page after login
Right now I can login, and post a new post which saves it in the database.
This is the home.js functional componenet which the user sees after a login:
import '../App.css';
import { useHistory } from "react-router-dom";
import React , {useState, useEffect} from 'react';
import jwt_decode from 'jwt-decode'
import logo from '../images/home-logo.png';
import {Col,Form,Input,Button,Card,CardTitle,Navbar,Nav,NavbarBrand} from 'reactstrap'
import { createPost,getUserPosts } from '../fucntions/user_functions'
function Home(){
var _decoded;
var _email;
let history = useHistory();
const[post_text,setPost] = useState('');
const handleChangePost = e =>{ setPost(e.target.value);};
function handlePost(e){
e.preventDefault();
const toPost = {
post :post_text, email :_email
}
createPost(toPost).then(res =>{
setPost('')
})
}
function getPosts() {
const container ={
email:_email
}
getUserPosts(container).then(res=>{
})
}
function handleLogout (e) {
e.preventDefault();
localStorage.removeItem('usertoken')
history.push(`/login`)
}
useEffect(() =>{
if (localStorage.getItem("usertoken") === null) {
history.push('/login')
} else {
const token = localStorage.usertoken
const user_email = localStorage.useremail
const decoded = jwt_decode(token)
_decoded = decoded;
_email = decoded.email
getPosts()
};
});
return (
<div className = "box">
<div>
<Navbar color="light" light expand="md">
<Nav>
<NavbarBrand type = "button" onClick = {handleLogout}>Logout</NavbarBrand>
</Nav>
</Navbar>
<div className = "wrapper">
<Card body outline color="secondary" className = "card-home " >
<CardTitle><img src={logo} alt="logo"></img>Create post</CardTitle>
<Form onSubmit = {handlePost}>
<Input id = "tx" name = "input1" type = "textarea" value = {post_text} placeholder="Enter your post here" onChange= {handleChangePost}></Input>
<br></br>
<Col sm={{ span: 10, offset: 5 }}>
<Button outline color="primary" type="submit">Post!</Button>
</Col>
</Form>
</Card>
</div>
</div>
</div>
)
}
export default Home;
I have implemented a getPosts method in the backend which gives back an array of the posts
router.post("/getPosts",
async (req, res) => {
const {email,} = req.body;
try {
let user = await User.findOne({email:email});
allPosts = user.posts
res.render('/home',{posts : hello})
} catch (e) {
console.error(e);
res.json("Error")
}
}
);
As you can see above, in the function getPosts(), the response is an Array of all the post's ids the user has posted, they are stored in the mongodb collection called "posts"
And after calling that function, I can iterate over them:
function getPosts() {
const container ={
email:_email
}
getUserPosts(container).then(res=>{
forEach(res.posts) {
}
})
}
I want to render all those posts live, so each time the user posts a new post, it will show right after the Create post div you can see in the picture, What's the best way?
Thanks

First define your posts collection state:
const [allPosts, setAllPosts] = useState([]);
Then every time you successfully save a post in the database, append it to that state:
function handlePost(e){
e.preventDefault();
const toPost = {
post :post_text, email :_email
}
createPost(toPost).then(res =>{
setPost('')
setAllPosts(allPosts.concat(toPost);
})
}
The same goes for getPosts:
function getPosts() {
const container ={
email:_email
}
getUserPosts(container).then(res=>{
setAllPosts(res.data); // <-- if the data is the same structure as the created before
})
}
Then you can render them in an example way:
return (
<div className = "box">
<div>
<Navbar color="light" light expand="md">
<Nav>
<NavbarBrand type = "button" onClick = {handleLogout}>Logout</NavbarBrand>
</Nav>
</Navbar>
<div className = "wrapper">
<Card body outline color="secondary" className = "card-home " >
<CardTitle><img src={logo} alt="logo"></img>Create post</CardTitle>
<Form onSubmit = {handlePost}>
<Input id = "tx" name = "input1" type = "textarea" value = {post_text} placeholder="Enter your post here" onChange= {handleChangePost}></Input>
<br></br>
<Col sm={{ span: 10, offset: 5 }}>
<Button outline color="primary" type="submit">Post!</Button>
</Col>
</Form>
<div>
{
allPosts.map(post => {
return <div><div>email: {post.email}</div><div>post: post.post</div></div>
})
}
</div>
</Card>
</div>
</div>
</div>
)
Feel free to change the HTML structure, so it matches your design

Related

Cors error when sending data from front-end client side react component to node.js server [duplicate]

This question already has answers here:
CORS error even after setting Access-Control-Allow-Origin or other Access-Control-Allow-* headers on client side
(2 answers)
Closed 7 months ago.
I am attempting to send data from my client side react component below to my node.js server. Within my console it shows the data is being passed through from client side to server. However, I am getting the following cors error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:4000/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
I am not sure why I am still getting this as I have required and implemented cors below, as well as put res.setHeader("Access-Control-Allow-Origin", "*"); in the post request.
Any help would be greatly appreciated! Thank you :)
UPDATE
I solved the issue by enabling the cors middleware app.use(cors())
node server.js file
const express = require("express");
const cors = require("cors");
const app = express();
const port = 4000;
app.post("/", cors(), (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
const emailInfo = req.body.emailUserInput;
console.log(emailInfo);
// sendgrid details //
require("dotenv").config();
const sgMail = require("#sendgrid/mail");
const apikey = process.env.SENDGRID_API_KEY;
sgMail.setApiKey(apikey);
const msg = {
to: emailInfo,
from: "email",
subject: "Sending with Twilio SendGrid is Fun",
text: "and easy to do anywhere, even with Node.js",
html: "<strong>and easy to do anywhere, even with Node.js</strong>",
};
// email sending logic //
//ES8
(async () => {
try {
await sgMail.send(msg);
} catch (error) {
console.error(error);
if (error.response) {
console.error(error.response.body);
}
}
})();
});
app.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
client-side react component
import "../StyleComponents/CreateEvent.css";
import { useState } from 'react';
import { db } from '../firebase';
import { uid } from "uid";
import { set, ref } from "firebase/database";
import Header from "./Header";
import { useNavigate } from 'react-router-dom';
import { getStorage, ref as sref, uploadBytes } from "firebase/storage";
import PlacesAutocomplete from 'react-places-autocomplete';
import { geocodeByAddress, getLatLng } from 'react-places-autocomplete';
import axios from 'axios';
function CreateEvent() {
// store user inputs in state //
const [titleUserInput, setTitleUserInput] = useState('');
const [dateUserInput, setDateUserInput] = useState('');
const [timeUserInput, setTimeUserInput] = useState('');
const [address, setAddress] = useState('');
const [setCoordinates] = useState({
lat: null,
lng: null,
})
const [headerUserInput, setHeaderUserInput] = useState('');
const [detailsUserInput, setDetailsUserInput] = useState('');
const [lengthUserInput, setLengthUserInput] = useState('');
const [emailUserInput, setEmailUserInput] = useState('');
const [userSubmit, setUserSubmit] = useState('');
const [error, setError] = useState(false);
// Create a root reference for storing event photos //
const storage = getStorage();
// handle changing user input data //
const handleTitleChange = (e) => {
setTitleUserInput(e.target.value);
}
const handleDateChange = (e) => {
setDateUserInput(e.target.value);
}
const handleTimeChange = (e) => {
setTimeUserInput(e.target.value);
}
const handleSelect = async (value) => {
const results = await geocodeByAddress(value);
const latLng = await getLatLng(results[0]);
setAddress(value);
setCoordinates(latLng);
}
const handleDetailsChange = (e) => {
setDetailsUserInput(e.target.value);
}
const handleLengthChange = (e) => {
setLengthUserInput(e.target.value);
}
const handleHeaderChange = (e) => {
// Create a root reference for storing event photos //
setHeaderUserInput(e.target.files[0]);
}
const handleEmailChange = (e) => {
setEmailUserInput(e.target.value);
}
const navigate = useNavigate();
// make call to the backend database to send email user input data //
const url = 'http://localhost:4000';
const getEmailInput = () => {
axios.post(url, {emailUserInput}).then((res) => {
console.log(res);
}).catch(console.log('error'));
}
// submit user data to database with unique ID for each event //
const writeToDataBase = () => {
let uuid = uid()
if (titleUserInput.length === 0 || dateUserInput.length === 0 || timeUserInput.length === 0 || address.length === 0 || emailUserInput.length === 0) {
setError(true);
}
if (titleUserInput && dateUserInput && timeUserInput && address && emailUserInput) {
const storageRef = sref(storage, uuid);
set(ref(db, `/${uuid}`), {
EventPhoto: headerUserInput,
EventTitle: titleUserInput,
EventDate: dateUserInput,
EventTime: timeUserInput,
EventLength: lengthUserInput,
EventLocation: address,
EventDetails: detailsUserInput,
});
getEmailInput('');
setUserSubmit('');
uploadBytes(storageRef, headerUserInput).then(() => {
navigate(`/EventCreated/${uuid}`);
});
}
}
return (
<>
< Header />
<div className="event-creation-container">
<h1>Create a New Event</h1>
<form>
<div className="event-name-container event-input">
<label for="eventTitle">Name of Event<span>*</span></label>
<input type="text" id="EventTitle" value={titleUserInput} onChange={handleTitleChange} />
{error && titleUserInput === '' ?
<label id="form-validation-label">Event name must be filled</label> : ""}
</div>
<div className="date-time-length">
<div className="date-input-container event-input">
<label for="Date">Date<span>*</span></label>
<input type="date" id="EventDate" value={dateUserInput} onChange={handleDateChange} />
{error && dateUserInput === '' ? <label id="form-validation-label">Event date must be filled</label>: ""}
</div>
<div className="time-input-container event-input">
<label for="Time">Time<span>*</span></label>
<input id="EventTime" type="time" name="time" timezone="timezone" value={timeUserInput} onChange={handleTimeChange} />
</div>
{error && timeUserInput === '' ? <label id="form-validation-label">Event time must be filled</label> : ""}
<div className="length-input-container event-input">
<label for="Length">Length</label>
<input id="EventLength" type="text" value={lengthUserInput} onChange={handleLengthChange} />
</div>
</div>
<div className="location-input-container event-input">
<label for="Location">Location<span>*</span></label>
<PlacesAutocomplete onChange={setAddress} value={address} onSelect={handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<input id="EventLocation" {...getInputProps()} />
<div className="location-suggestions">
{loading ? <div>...loading</div> : null}
{suggestions.map((suggestion) => {
const style = {
backgroundColor: suggestion.active ? "#41b6e6" : "#fff"
};
return <div {...getSuggestionItemProps(suggestion, { style })}>{suggestion.description}</div>
})}
</div>
</div>
)}
</PlacesAutocomplete>
</div>
{error && address ==='' ? <label id="form-validation-label">Event location must be filled</label> : ""}
<div className="details-input-container event-input">
<label for="Event_Details">Event Details</label>
<textarea type="text" id="EventDetails" value={detailsUserInput} onChange={handleDetailsChange} />
</div>
<div className="header-input-container event-input">
<div className="upload-image-flex-container">
<label for="header_image">Upload Header Image (optional)</label>
<input className="upload-input" type="file" id="
EventImage" name="filename" accept="image/png, image/jpeg" onChange={handleHeaderChange} />
</div>
</div>
<div className="orangizer-email-container">
<label for="organizer-email">Organizer's Email<span>*</span></label>
<p>The event page link will be sent to your email</p>
<input id="EventEmail" type="email" name="email" value={emailUserInput} onChange={handleEmailChange} />
{error && emailUserInput === '' ? <label id="form-validation-label">Event organizer's email must be entered</label> : ""}
</div>
<div className="create-event-btn-container">
<button className="event-create-button" type="button" value={userSubmit} onClick={writeToDataBase}>Create Event</button>
</div>
</form>
</div>
</>
)}
export default CreateEvent;
Your issue here may be the browser sending out a CORS preflight request which is then followed by your POST request. This is an OPTIONS request sent automatically which is where it is expecting to get the CORS headers from. See here.
Currently even though you've implemented CORS on your post endpoint, it's not catching that preflight request which is likely what you need to do. The 'cors' npm package describes that on their page. Implementing this should then allow the browser to recognise the origin so you no longer get errors back.

how to post form data to the server backend

Form.js
import "./form.css";
import React, {useEffect,useState} from "react";
import {addBeauty,deleteB} from "./beauty";
import Modal from "./Modal";
import axios from 'axios';
export default function CreateForm() {
const [Name, setName] = useState("");
const [Intro, setIntro] = useState("");
const [isOpen, setIsOpen] = useState();
const [backendData, setBackendData] = useState([{}]);
useEffect(()=>{
fetch("http://localhost:5000/api").then(
response=>response.json()
).then(
data=>{ setBackendData(data)}
)
},[]);
const handleSubmit = (event)=>{
event.preventDefault();
axios.post("http://localhost:5000/api",{
id: userList[userList.length - 1].id + 1, Name:Name, Introduction:Intro
}).then(res=>{
console.log(res.data);
})
}
return (
<div className="container">
<form className="add" onSubmit={handleSubmit} >
<h2>User</h2>
<label htmlFor= "name">Name</label>
<input type="text" value={Name}
onChange={(event) => {setName(event.target.value);}}/>
<label htmlFor= "Intro">Introduction</label>
<input type="text" value={Intro}
onChange={(event) => {setIntro(event.target.value);}}/>
<p></p>
<p></p>
<div className = "press">
<button id = "1" type="submit">
Add Beauty
</button>
<button id = "2"
onClick={clearForm}
>
Clear Form
</button>
</div>
</form>
<br></br>
<br></br>
<br></br>
<div className="display">
{(typeof userData.user1 === 'undefined')?(
<h1>Loading</h1>):(
backendData.user1.map((user,i)=>{
return (
<div>
<h1> {user.Name}</h1>
<button onClick={()=>{
setIsOpen(user.id);
}}>View in popup</button>
<Modal open={isOpen === user.id} onClose={()=>setIsOpen(undefined)}>
<h3> {User.Introduction}</h3>
</Modal>
</div>
);})
)}
</div>
</div>
);
}
Server.js
const express = require('express');
const app = express();
const cors=require("cors");
const corsOptions ={
origin:'*',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
}
app.use(cors(corsOptions)) // Use this after the variable declaration
app.get("/api",(req,res)=> {
res.json({"user1":[
{
id: 1,
Name: "Isabella",
},
{
id:2,
Name: "Catalina
}
]})
});
app.listen(5000,()=>{
console.log("Server started on port 5000");
})
I create a from using react. And I try to send the formdata to backend and insert the formdata into the data stored at backend using axios.post. But it doesn't work. I know it's because I didn't add the prefix of backend data "user1" in axios.post. But I am not sure how to do that. Could anyone help me with this?
You have not created the route on the server correctly. You have opened a route for GETting "/api" but you need to open a route for POSTing
Replace this line:
app.get("/api",(req,res)=> {
with
app.post("/api",(req,res)=> {
Hi Here you need to create one route for post API as below
app.post("/api",(req,res)=> {
console.log(req.body) //here you got the requested data.
res.send("Success !");
});

React state clearing onChange [duplicate]

This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
Closed 9 months ago.
i am trying to build a calculation platform and i got an issue in that process when i am trying to clearing the state of my input value its last value store in it and because of that i am not able to perform certain task here the code
import React, { useState } from "react";
const App = () => {
const [buyPrice, setBuyPrice] = useState(8000);
const [buyAMount, setBuyAMount] = useState(0);
const [buy_total, setBuy_total] = useState(0);
const handleBuyChange = (e) => {
var { name, value } = e.target;
if (name == 'buyPrice') {
setBuyPrice(value);
}
if (name == 'buyAMount') {
setBuyAMount(value);
}
if (name == 'buy_total') {
setBuy_total(value);
}
console.log('alert',buyPrice,buyAMount,buy_total)
};
return (
<div>
<div>
<input
type={"number"}
name="buyPrice"
value={buyPrice}
onChange={(e) => handleBuyChange(e)}
/>
<input
type={"number"}
name="buyAMount"
value={buyAMount}
onChange={handleBuyChange}
/>
<input
type={"number"}
name="buy_total"
value={buy_total}
onChange={handleBuyChange}
/>
</div>
</div>
);
};
Heres the console:--
img
React setState functions are asynchronous in nature so the console.log showing previous values might be due to the fact that the state hasn't been updated yet so if you perform console.log outside the function you will get the updated values
import React, { useState } from "react";
const App = () => {
const [buyPrice, setBuyPrice] = useState(8000);
const [buyAMount, setBuyAMount] = useState(0);
const [buy_total, setBuy_total] = useState(0);
const handleBuyChange = (e) => {
var { name, value } = e.target;
if (name == 'buyPrice') {
setBuyPrice(value);
}
if (name == 'buyAMount') {
setBuyAMount(value);
}
if (name == 'buy_total') {
setBuy_total(value);
}
};
console.log('alert',buyPrice,buyAMount,buy_total)
return (
<div>
<div>
<input
type={"number"}
name="buyPrice"
value={buyPrice}
onChange={(e) => handleBuyChange(e)}
/>
<input
type={"number"}
name="buyAMount"
value={buyAMount}
onChange={handleBuyChange}
/>
<input
type={"number"}
name="buy_total"
value={buy_total}
onChange={handleBuyChange}
/>
</div>
</div>
);
};
total become read-only mode.
Check this code
const { useState } = React;
const App = () => {
const [buyPrice, setBuyPrice] = useState(8000);
const [buyAMount, setBuyAMount] = useState(0);
const [buy_total, setBuy_total] = useState(0);
const handleBuyChange = (e) => {
var { name, value } = e.target;
if (name == 'buyPrice') {
setBuyPrice(value);
}
if (name == 'buyAMount') {
setBuyAMount(value);
}
setBuy_total(buyPrice * buyAMount);
console.log('alert',buyPrice,buyAMount,buyPrice * buyAMount)
};
return (
<div>
<div>
<input
type="number"
name="buyPrice"
value={buyPrice}
onChange={(e) => handleBuyChange(e)}
/>
<input
type="number"
name="buyAMount"
value={buyAMount}
onChange={(e) =>handleBuyChange(e)}
/>
<input
type="number"
name="buy_total"
value={buyPrice * buyAMount}
readOnly
/>
</div>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>

React: How to update the DOM with API results

My goal is to take the response from the Google API perspective and display the value into a div within the DOM.
Following a tutorial : https://medium.com/swlh/combat-toxicity-online-with-the-perspective-api-and-react-f090f1727374
Form is completed and works. I can see my response in the console. I can even store the response into an object, array, or simply extract the values.
The issue is I am struggling to write the values to the DOM even though I have it saved..
In my class is where I handle all the API work
class App extends React.Component {
handleSubmit = comment => {
axios
.post(PERSPECTIVE_API_URL, {
comment: {
text: comment
},
languages: ["en"],
requestedAttributes: {
TOXICITY: {},
INSULT: {},
FLIRTATION: {},
THREAT: {}
}
})
.then(res => {
myResponse= res.data; //redundant
apiResponse.push(myResponse);//pushed api response into an object array
console.log(res.data); //json response
console.log(apiResponse);
PrintRes(); //save the values for the API for later use
})
.catch(() => {
// The perspective request failed, put some defensive logic here!
});
};
render() {
const {flirty,insulting,threatening,toxic}=this.props
console.log(flirty); //returns undefined, makes sense upon initialization but does not update after PrintRes()
return (
<div className="App">
<h1>Please leave a comment </h1>
<CommentForm onSubmit={this.handleSubmit} />
</div>
);
}
}
When I receive a response from the API I use my own function to store the data, for use later, the intention being to write the results into a div for my page
export const PrintRes=() =>{
// apiResponse.forEach(parseToxins);
// myResponse=JSON.stringify(myResponse);
for (var i = 0; i < apiResponse.length; i++) {
a=apiResponse[i].attributeScores.FLIRTATION.summaryScore.value;
b=apiResponse[i].attributeScores.INSULT.summaryScore.value;
c=apiResponse[i].attributeScores.THREAT.summaryScore.value;
d=apiResponse[i].attributeScores.TOXICITY.summaryScore.value;
}
console.log("hell0");//did this function run
// render(){ cant enclose the return in the render() because I get an error on the { , not sure why
return(
<section>
<div>
<p>
Your comment is:
Flirty: {flirty}
</p>
</div>
<div>
<p>
Your comment is:
insulting: {insulting}
</p>
</div>
<div>
<p>
Your comment is:
threatening: {threatening}
</p>
</div>
<div>
<p>
Your comment is:
toxic: {toxic}
</p>
</div>
</section>
);
}
Variables and imports at the top
import React from "react";
//needed to make a POST request to the API
import axios from "axios";
import CommentForm from "../components/CommentForm";
var myResponse;
var apiResponse= [];
let a,b,c,d;
let moods = {
flirty: a,
insulting:b,
threatening:c,
toxic:d
}
If I understand correctly You need to create a state where you store data from api.
States in react works like realtime stores to refresh DOM when something change. this is an example to use it
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
apiData: undefined
};
}
fetchData() {
this.setState({
apiData: "Set result"
});
}
render() {
const { apiData } = this.state;
return (
<div>
<button onClick={this.fetchData.bind(this)}>FetchData</button>
<h3>Result</h3>
<p>{apiData || "Nothing yet"}</p>
</div>
);
}
}
you can check it here: https://codesandbox.io/s/suspicious-cloud-l1m4x
For more info about states in react look at this:
https://es.reactjs.org/docs/react-component.html#setstate

I am getting a Warning: A component is changing an uncontrolled input of type text to be controlled

I building a simple todo app using the MERN stack with router and able to get it going except the edit part. I have 3 routes, the "Todos" page where i use axios to get the data from my express server route. The "Add" page for create new todo and the "Edit" page for editing and deleting. Here's my todos page where each todo has a button that takes the id as a url parameter unto the Edit page.
That little pencil/paper icon on each todo is a button link that get's the ID on click. Here's my Edit page with the data.
The warning:
Here's my Todos page i'm using a custom hook to fetch the data from express server route:
import React from 'react';
import useGetAPI from '../custom_hooks/useGetAPI';
import Todo from './todo_item/Todo';
const Todos = () =>{
const data = useGetAPI('http://localhost:4000');
return (
<div className="page">
<div className="page-header">
<h1>Todo Lists</h1>
</div>
<div className="page-content">
<ul className="todo-list">
{
data.map((todo)=><Todo todo={todo} key={todo._id}/>)
}
</ul>
</div>
</div>
);
}
export default Todos;
Here's my custom hooks for fetching data - used in Todos.
import {useState,useEffect} from 'react';
import axios from 'axios';
const useGetAPI = (url)=>{
const [data,setData] = useState([]);
useEffect(()=>{
const fetchData = async ()=>{
const response = await axios.get(url);
const data = [...response.data];
const error = response.error;
if(error)
console.log(error)
else{
console.log(data);
setData(data);
}
};
fetchData();
},[url])
return data;
}
export default useGetAPI;
Here's my Edit Page
import React,{useState, useEffect, useContext, useCallback} from 'react';
import useGetApiWithParams from '../custom_hooks/useGetApiWithParams';
import {FaTelegramPlane} from 'react-icons/fa';
import axios from 'axios';
import { matchPath } from 'react-router'
const EditTodo = (props) =>{
const todoID = props.match.params.id;
const [todo,setTodo] = useState(null);
const responseData = useGetApiWithParams('http://localhost:4000/edit',todoID);
console.log(`Todo id: ${todoID}`);
/* Set default data from database */
useEffect(()=>{
setTodo(responseData);
},[responseData,setTodo]);
const [description,setDescription] = useState('');
const [responsible,setResponsible] = useState('');
const [priority,setPriority] = useState('');
const [completed,setCompleted] = useState(false);
const handleDescription = useCallback((e)=>{
setDescription(e.target.value);
},[setDescription]);
const handleResponsible = useCallback((e)=>{
setResponsible(e.target.value);
},[setResponsible]);
const handlePriority = useCallback((e)=>{
setPriority(e.target.value);
},[setPriority]);
const handleCompleted = useCallback((e)=>{
setCompleted(!completed);
},[completed,setCompleted])
const handleSubmit = useCallback((e)=>{
e.preventDefault();
console.log('Form submitted');
console.log(`Description ${description}`);
console.log(`Description ${responsible}`);
console.log(`Description ${priority}`);
console.log(`Description ${completed}`);
const updatedTodo = {
description,
responsible,
priority,
completed: false
}
axios.put(`http://localhost/4000/edit/${props.match.params.id}`, updatedTodo)
.then(res=>console.log(res.data))
.catch(function (error) {
console.log(error);
});
},[description,responsible,priority,completed,props.match.params.id]);
return (
<div className="page">
<div className="page-header">
<h1>Edit Todo</h1>
</div>
<div className="page-content">
<form id="edit-todo-form" className="todo-form" onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="description">Description:</label>
<input id="description" type="text" className="form-control" onChange={handleDescription} value={responseData.description} />
</div>
<div className="form-group">
<label htmlFor="responsible">Responsible:</label>
<input id="responsible" type="text" className="form-control" onChange={handleResponsible} value={responseData.responsible} />
</div>
<div className="form-group">
<label htmlFor="priorities">Priorities:</label>
<div id="priorities" className="form-radios">
<label htmlFor="radio1" className="radio-label">
<input name="priorityOptions" type="radio" id="radio1" value={responseData.priority} checked={priority === 'Low'} onChange={handlePriority}/>
<span className="radiomark"></span>
<span className="radiotext">Low</span>
</label>
<label htmlFor="radio2" className="radio-label">
<input type="radio" id="radio2" value={responseData.priority} checked={priority === 'Medium'} onChange={handlePriority}/>
<span className="radiomark"></span>
<span className="radiotext">Medium</span>
</label>
<label htmlFor="radio3" className="radio-label">
<input type="radio" id="radio3" value={responseData.priority} checked={priority === 'High'} onChange={handlePriority}/>
<span className="radiomark"></span>
<span className="radiotext">High</span>
</label>
</div>
</div>
<div className="form-group">
<label htmlFor="todo_completed">Status:</label>
<div id="todo_completed">
<label htmlFor="checkcompleted" className="check-label">
<input type="checkbox" id="checkcompleted" value={responseData.completed} onChange={handleCompleted}/>
<span className="checkmark"></span>
<span className="checktext">Completed</span>
</label>
</div>
</div>
<div className="form-group">
<button type="submit" className="form-btn"><FaTelegramPlane />Save Changes</button>
</div>
</form>
</div>
</div>
);
}
export default EditTodo;
Here's my custom hook for fetching data based on the Todo ID i get from the url:
import { useState,useEffect } from 'react';
import axios from 'axios';
const useGetApiWithParams = (url,params)=>{
const [data,setData] = useState([]);
useEffect(()=>{
const fetchData = async ()=>{
const response = await axios.get(`${url}/${params}`);
const data = response.data;
const error = response.error;
if(error)
console.log(`Error: ${error}`)
else{
console.log(...data);
setData(...data);
}
};
fetchData();
},[url,params])
return data;
}
export default useGetApiWithParams;
And the url with id param from MongoDB:
How to solve this? I tried the placeholder and set it's value to the response data from api but it only works for text boxes, what about the radio buttons and checkboxes? They don't seem to set the default value. For example the radio button for setting the priority value={responseData.priority} doesn't set the value as you can see here:
What i would like to happen is: from the Todos page on clicking the edit button, the edit page with a form already filled with values based on the todo id from the url parameter and be able to edit the values as well. Need help, thanks!

Resources