Basic post request for users using express (React) - node.js

I am having serious issues trying to solve this issue and any help would be appreciated greatly
So all I am trying to do is a simple register activity for users where I will be able to sign them up to the site.
I am using mssql, and express.
This is My Register.js. All I want is for the details input into the buttons to be passed through to the json body so it can then be used in my server.js.
Register.js
class AddUsers extends React.Component {
constructor() {
super();
this.state = { users: [] };
this.onSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const data = { email: this.ref.email, password: this.ref.password };
// const data = { name: "", password: "" };
fetch("/admin-Add-Users", {
method: "POST", // or 'PUT'
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
console.log("Success:", data);
})
.catch(error => {
console.error("Error:", error);
});
}
render() {
console.log(this.state.users);
return (
<div>
<LoginForm></LoginForm>
<form onSubmit={this.onSubmit}>
<input type="text" placeholder="email" ref="email" />
<input type="text" placeholder="password" ref="password" />
<input type="submit" />
</form>
</div>
);
}
}
This is my server.js (config file is working). Here all I want is for the data previously added to be stored in my database (SQL server).
app.post("/admin-Add-Users", function(req, res) {
const { password, email } = req.body;
var request = new sql.Request();
// query to the database and get the records
request.query( "insert into Login (email, password) values ('"+email+"','"+password+"')", function(err, recordset) {
if (err) console.log(err);
});
res.send({ message: "Success" });
});
I have no idea how to get the data from the inputs to just be stored through my server.js. Please any help or examples are appreciated. I am new to react so please explain like I am five years old.
Error I am now receiving
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the method `isPropagationStopped` on a released/nullified synthetic event. This is a no-op function. If you must keep the original synthetic event around, use event.persist().

You should try to avoid use refs in react unless you have a good reason to use them (some things like animations need to be controlled imperatively).
The React way is to do things declaratively with state, so changing an input updates the associated state field, and then the onSubmit function takes the values from state. Something like this:
class AddUsers extends React.Component {
constructor() {
super();
this.state = { users: [], email: '', password: '' };
this.onSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const data = { email: this.state.email, password: this.state.password };
fetch("/admin-Add-Users", {
method: "POST", // or 'PUT'
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
console.log("Success:", data);
})
.catch(error => {
console.error("Error:", error);
});
}
render() {
console.log(this.state.users);
return (
<div>
<LoginForm></LoginForm>
<form>
<input type="text" placeholder="email" value={this.state.email} onChange={e =>
this.setState({email: e.target.value})} />
<input type="text" placeholder="password" value={this.state.password} onChange={e =>
this.setState({password: e.target.value})} />
<input type="submit" onPress={this.onSubmit} />
</form>
</div>
);
}
}

Related

MERN CRUD Can't edit the input fields when try to edit a user

Im trying to make my project with MERN and I'm doing the CRUD of a user, but when I get to the part of updating the user, I use the value with the mongoDB data, to be already filled when the admin get's in the page.
But when I try to edit it, I can't even type or delete inside the field...
This is my code on React with the fetch to get the information from the backend:
const EditUtilizador = () => {
const { userId } = useParams();
const [loading, setLoading] = useState(true);
const [userInfo, setUserInfo] = useState([]);
const nav = useNavigate();
const { register, handleSubmit } = useForm();
const onSubmit = (data) => putUser(data);
useEffect(() => {
fetch(`/userdb/users/${userId}`, {
headers: { Accept: "application/json" },
})
.then((response) => response.json())
.then((response) => {
setLoading(false);
setUserInfo(response);
});
return () => setUserInfo([]);
}, []);
const putUser = (data) => {
fetch(`/userdb/users/${userId}`, {
headers: { "Content-Type": "application/json" },
method: "PUT",
body: JSON.stringify(data),
})
.then((response) => {
if (response.ok) {
alert("Utilizador atualizado com sucesso");
nav("/admin/utilizadores");
} else {
alert("Algo de errado não esta certo");
}
})
.catch((error) => {
console.log("Error:", error);
});
};
if (loading) {
return (
<>
<HeaderAdmin />
<h1>A carregar</h1>
</>
);
}
return (
<>
<HeaderAdmin />
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="text"
name="name"
value={`${userInfo.name}`}
{...register("name")}
/>
<br />
<input
type="text"
name="email"
value={`${userInfo.email}`}
{...register("email")}
/>
<br />
<input
type="password"
name="password"
placeholder="Nova Password"
{...register("password")}
/>
<br />
<br />
<button type="submit">Atualizar Conta</button>
</form>
</>
);
};
As you can see in the return, inside the input I get the value already the value that is in the database, but for some reason I don't know, I'm not able to edit it...
It looks like this in the page:
I try to type inside the field and I can't change what's in it?
What can I do?
const [userInfo, setUserInfo] = useState([]);
Since userInfo is array and you are storing value in input as userInfo.name which is basically method to get key value in object so make it object add key value as default
const [userInfo, setUserInfo] = useState({
name:"",
email:""
});
and to change input use onChange method on input
i.e
<input
type="text"
name="name"
value={`${userInfo.name}`}
onChange={((e)=>{
setUserInfo(pre=>{
pre.name=e.target.value;
})
})}
/>
this change will you to edit and update as well and pass the update date in put api

Next js API resolved without sending a response for /api/contact, this may result in stalled requests

Getting API resolved without sending a response for /api/contact, this may result in stalled request on the following API route in Next.js. It's using sendgrid and the email gets sent but I'm not getting a response back so I can handle errors or success message.
I've updated the below with the front end code. I'm now not getting that error but on the front end the call 'const response = await fetch('/api/contact'..' doesn't return anything
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_APIKEY);
export default function handler(req, res) {
if (req.method === 'POST') {
const email = {
from: process.env.EMAIL_FROM,
to: process.env.EMAIL_TO,
subject: 'Website Contact Form',
html: `<div>
<div><strong>Name:</strong> ${req.body.name}<br/></div>
<div><strong>Phone:</strong> ${req.body.phone}<br/></div>
<div><strong>Email:</strong> ${req.body.email}<br/></div>
<div><strong>more:</strong> ${req.body.more}<br/></div>
</div>`,
};
try {
return sgMail
.send(email)
.then(() => {
console.log('res1', res);
//return res;
return res.status(200).end();
})
.catch((error) => {
console.log('error', error);
return res.status(500).send(error);
});
} catch (error) {
console.log('error 2', error);
res.json(error);
return res.status(405).end();
}
}
}
import React from 'react';
import { Formik, Form } from 'formik';
import * as Yup from 'yup';
import TextAreaField from './textAreaField';
import TextField from './textfield';
function ContactForm() {
return (
<Formik
initialValues={{
name: '',
phone: '',
email: '',
more: '',
}}
validationSchema={Yup.object({
name: Yup.string().required('Required'),
phone: Yup.string().required('Required'),
email: Yup.string().email('Invalid email address').required('Required'),
more: Yup.string().required('Required'),
})}
onSubmit={async (values, { setSubmitting }) => {
setSubmitting(true);
const response = await fetch('/api/contact', {
body: JSON.stringify({
name: values.name,
phone: values.phone,
email: values.email,
more: values.more,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
});
console.log('response', response);
const data = await response.json();
console.log('response 1', data);
setSubmitting(false);
}}
>
{(props) => {
const { values, setFieldValue } = props;
console.log('props', props);
console.log('values', values);
return (
<div className="c-contact-form">
<Form className="form">
<TextField label="Customer Name" name="name" type="text" placeholder="John" />
<TextField label="Phone Number" name="phone" type="text" placeholder="07909765432" />
<TextField label="Email Address" name="email" type="email" placeholder="John#gmail.com" />
<TextAreaField label="More" name="more" placeholder="More details" />
<button type="submit" className="c-btn">
Submit
</button>
</Form>
{values.success && (
<div>
<p>Your enquiry has been successfully submitted.</p>
</div>
)}
{values.nosend && (
<div>
<p>OOPS, something went wrong but we know about it. please contact us via email or phone</p>
</div>
)}
</div>
);
}}
</Formik>
);
}
export default ContactForm;
You need to send a response back like the following
try {
sgMail
.send(email)
.then(() => {
console.log('res', res.json);
return res.status(200).end();
})
.catch((error) => {
console.log('error', error);
return res.status(500).send(error);
});

How do I use data from POST request for the next GET request

I'm trying to build a web app that uses Spotify API now. I want it to send a search keyword that an user submits to the server and send back its search result to the front end. The problem is I get a 404 status code for the fetch call. The POST request works fine.
Main.js
import React, { Component } from "react";
import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
axios
.post(
"http://localhost:4000/search_result",
{
keyword: this.state.keyword,
},
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
}
)
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
}
componentDidMount() {
fetch("http://localhost:4000/api")
.then((res) => res.json)
.then((artists) => {
this.setState({ artists });
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map((elem) => (
<SingerCard
images={elem.images}
name={elem.name}
artists={this.state.artists}
/>
))}
{console.log(this.state.artists)}
</div>
<br />
</div>
);
}
}
export default Main;
server.js
const express = require("express");
const SpotifyWebApi = require("spotify-web-api-node");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
const port = 4000 || process.env.PORT;
require("dotenv").config();
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
// Create the api object with the credentials
var spotifyApi = new SpotifyWebApi({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
});
// Retrieve an access token.
spotifyApi.clientCredentialsGrant().then(
function (data) {
console.log("The access token expires in " + data.body["expires_in"]);
console.log("The access token is " + data.body["access_token"]);
// Save the access token so that it's used in future calls
spotifyApi.setAccessToken(data.body["access_token"]);
},
function (err) {
console.log("Something went wrong when retrieving an access token", err);
}
);
app.post("/search_result", (req, res) => {
console.log(req.body.keyword);
spotifyApi.searchArtists(req.body.keyword).then(function (data) {
var search_res = data.body.artists.items;
res.json(search_res);
app.get("http://localhost:/api", (req, res) => {
res.json(search_res);
res.end();
});
res.end();
}),
function (err) {
console.log(err);
};
});
app.listen(port, () => console.log(`It's running on port ${port}`));
I think the app.get() in the app.post() causes the error but I can't figure out another way to send the search result back.
You're getting a 404 because the get method is not correctly defined.
Update your server code to define the get method to just keep the pathname, like this:
app.get("/api", (req, res) => {
// ...
}
Currently, you are defining this route inside the app.post. The get route definition should be outside of the post route.
Use Axios.get
import React, { Component } from "react";
// import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
const headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
};
axios.post(
"https://jsonplaceholder.typicode.com/users",
{ keyword: this.state.keyword },
{ headers: headers }
)
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then(res => {
this.setState({
artists: res.data
});
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map(elem => (
<div key={elem.id}>
<ul>
<li>{elem.name}</li>
</ul>
</div>
))}
</div>
</div>
);
}
}
export default Main;

React : LocalStorage with a non-null value always

Hello I am using localStorage to save my jwt token from my api
But it is saving my token even if I close shut down the node server and etc.
and I would need to do a login check
here is my server route
app.route('/login')
.post(async (req,res)=>{
try {
const response = await usersControllers.signin(req.body);
const login = response.login;
console.log(login);
if(login.id && login.isValid){
const payload = {id: login.id};
res.json({
token: jwt.sign({data:payload}, app.config.jwt.secret,{expiresIn: '60'}),
response
});
}else{
console.log('entrou here');
res.sendStatus(HttpStatus.UNAUTHORIZED);
}
} catch (error) {
console.log('entrou here');
console.error(error.message);
res.sendStatus(HttpStatus.UNAUTHORIZED);
}
})
and in my front end react
i have this in my login:
import React, { Component } from 'react';
import {Form,FormGroup, Label, Input, Button, Alert} from 'reactstrap';
import Header from '../../components/header';
export default class Login extends Component {
constructor(props) {
super(props)
console.log(this.props);
this.state = {
message: this.props.location.state?this.props.location.state.message: '',
};
}
signIn = () => {
const data = {login:this.login,password:this.password};
const requestInfo = {
method:'POST',
body: JSON.stringify({data}),
headers: new Headers({
'Content-Type': 'application/json'
}),
};
fetch('http://localhost:9000/login', requestInfo)
.then(response => {
if(response.ok){
return response.json();
}
throw new Error("Login Invalido..")
})
.then(token => {
localStorage.setItem('token', token.token);
this.props.history.push("/users");
return;
})
.catch(e => {
this.setState({message: e.message})
});
}
render(){
return(
<div className="col-md-6">
<Header title="ReactJS Login"/>
<hr className="my-3"/>
{
this.state.message !== ''? (
<Alert color="danger" className ="text-center"> {this.state.message}</Alert>
) : ''
}
<Form>
<FormGroup>
<Label for="login">Login</Label>
<Input type="text" id="login" onChange={e => this.login = e.target.value } placeholder="Informe seu login" />
</FormGroup>
<FormGroup>
<Label for="password">Senha</Label>
<Input type="text" id="password" onChange={e => this.password = e.target.value } placeholder="Informe sua senha"/>
</FormGroup>
<Button color="primary" onClick={this.signIn}> Entrar </Button>
</Form>
</div>
);
}
}
here i set my jwt in localstorage:
.then(token => {
localStorage.setItem('token', token.token);
this.props.history.push("/users");
return;
})
in my other js file
my auth about jwt
const isAuth = () => {
console.log(localStorage.getItem('token'));
if(localStorage.getItem('token') !== null) {
console.log("entrou aq2");
return true;
}
return false;
};
in console.log(localStorage.getItem('token')); have value !== all time
Even without logging in with my api
The reason your
localStorage.getItem('token') !== null
is returning true is because you are using localStorage. localStorage's values does not expire therefore your value is stored in your localStorage until you call
localStorage.removeItem('token')
If you want your token be deleted after each time you close your browser, use sessionStorage instead. You can read more about authenticating with SPA here
Use JSON.stringify() to save in localstorage
.then(token => {
localStorage.setItem('token', JSON.stringify(token.token));
this.props.history.push("/users");
return;
})
and use JSON.parse() to get from localstorage
const isAuth = () => {
if(JSON.parse(localStorage.getItem('token')) !== null) {
console.log("entrou aq2");
return true;
}
return false;
};

Trouble with sending data from react to node

I'm trying to build a website where user post queries and other users are able to answer in it. I'm trying to implement various tags in it using react-tags-input module. However i'm having problem in sending those tags to node server. Help needed.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router-dom';
import '../Login.css';
import "./Home.css";
import Post from "./Post";
import { WithContext as ReactTags } from 'react-tag-input';
const KeyCodes = {
comma: 188,
enter: 13,
};
const delimiters = [KeyCodes.comma, KeyCodes.enter];
class query extends Component {
constructor() {
super();
this.state = {
userquery:'',
queries:[],
tags: [],
suggestions: [
{ id: "Javascript", text: "Javascript" },
{ id: "Java", text: "Java" },
{ id: 'node.js', text: 'node.js' },
{ id: 'react.js', text: 'react.js' },
{ id: 'express', text: 'express' },
{ id: 'bootstrap', text: 'bootstrap' },
{ id: 'python', text: 'python' },
{ id: 'c++', text: 'c++' }
]
};
this.handleDelete = this.handleDelete.bind(this);
this.handleAddition = this.handleAddition.bind(this);
this.handleDrag = this.handleDrag.bind(this);
}
onChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value;
this.setState(state);
}
componentDidMount(){
fetch('/query').
then((Response)=>Response.json()).
then(data =>{
this.setState({queries:data.reverse()});
})
}
handleDelete(i) {
const { tags } = this.state;
this.setState({
tags: tags.filter((tag, index) => index !== i),
});
}
handleAddition(tag) {
this.setState(state => ({ tags: [...state.tags, tag] }));
}
handleDrag(tag, currPos, newPos) {
const tags = [...this.state.tags];
const newTags = tags.slice();
newTags.splice(currPos, 1);
newTags.splice(newPos, 0, tag);
// re-render
this.setState({ tags: newTags });
}
render() {
const {userquery } = this.state;
const { tags, suggestions } = this.state;
return (
<div class="container">
<form action="/queries" method="POST">
<h2 class="form-signin-heading" color="blue">Want to ask something? ask here!</h2>
<label for="inputQuery" class="sr-only">query</label>
<textarea type="text" class="form-control" placeholder="want to ask something? ask here!" name="userquery" required/>
<br/>
<div class="form-group ">
<input class="form-control" type="text" name="image" placeholder="image url"/>
</div>
<div class="form-group ">
<ReactTags
name='tags'
tags={tags}
suggestions={suggestions}
handleDelete={this.handleDelete}
handleAddition={this.handleAddition}
handleDrag={this.handleDrag}
delimiters={delimiters}
/>
</div>
<br/>
<button class="btn btn-lg btn-primary btn-block" >Ask</button>
</form>
<section>
<h2> Recent Posts</h2>
</section>
{this.state.queries.map((item, key) => {
return (<Post item={item} key={key} />)
}
)
}
</div>
);
}
}
export default query;
server file - I'm able to get userquery and image but req.body.tags is returning an empty object.
app.post("/queries",isLoggedIn,function(req,res){
var postQuery =req.body.userquery;
var userImages =req.body.image;
console.log(req.body.tags);
username=req.user.username;
var newQuery = {
name:username,
image:userImages,
description:postQuery
}
Query.create(newQuery,function(err,newlyCreated){
if(err){
console.log(err);
}
else{
res.redirect("http://localhost:3000/home");
}
})
// res.send("you hit the post route")
});
Edited
onSubmit = e => {
e.preventDefault()
const {someText, tags} = this.state
const data = {someText, tags: tags.map(x => x.id)}
alert(`Submitting: ${JSON.stringify(data)}`)
fetch(
'queries',
{
method: 'POST',
mode: "cors", // no-cors, cors, *same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin",
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
},
)
}
server.js
app.post("/queries",function(req,res){
console.log("tags are:-",req.body)
});
output
tags are:- {}
The problem is in react-tags storing selected tags as a bunch of span elements, not input. So, these values are not included in form data being submitted.
You have to handle form submit logic manually.
Here is an example of handlers you need to add/change:
onSubmit = e => {
e.preventDefault() // stop default form submission
const { field1, field2, tags } = this.state // select form input values to submit
const data = { field1, field2, tags: tags.map(t => t.id) } // create an object to submit
fetch(
'url',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
},
) // send POST request
}
onChange = e => this.setState({ [e.target.name]: e.target.value }) // for plain inputs
onAdd = tag => this.setState(state => ({ tags: [...state.tags, tag] })) // for tags input
render() {
return (
<form onSubmit={this.onSubmit}>
<input name="field1" onChange={this.onChange} />
<input name="field2" onChange={this.onChange} />
<ReactTags
tags={this.state.tags}
handleAddition={this.onAdd}
/>
<button type="submit">submit</button>
</form>
)
}
Working example is in this sandbox.
Result is here: https://prnt.sc/kg2j9p
Update: now codesandbox uses fetch and posts the form data, you can try to submit form and see outgoing request in network tab in browser dev tools.

Resources