Can not load array from backend - node.js

After a search, I am sending the result to frontend in the form of array. But I am not being able to get that array in frontend using fetch. Through postman I am able to get the result from the backend but I am not able to get it in the frontend. In another file, I have set axios.post as well and exported from there and imported in frotend.
I am beginner so I might have written a bad code, any help will mean a lot.
In frontend :
class Hostel extends Component{
constructor (){
super();
this.state = {
country : '',
city : '',
category : '',
errors : {}
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({
errors: nextProps.errors
});
}
}
onChangeAddOptions = e => {
this.setState({ [e.target.id]: e.target.value });
};
addOption = e => {
e.preventDefault();
const newOption = {
country : this.state.country,
city : this.state.city,
category:this.state.category,
}
this.props.saveOptions(newOption,this.props.history);
};
getHostels = async ()=> {
console.log("getHostel function is called");
const response = await fetch('http://localhost:5000/api/users/hostel',{
method : "POST",
// headers:{
// "Content-Type" : "application/json"
// },
})
.then((response)=> {response.json()})
.then((data)=>{
console.log("inside data");
console.log(data);
})
.catch(e=>{
console.error(e.error);
})
console.log("From outside of data");
console.log(response);
}
componentDidMount(){
this.getHostels();
}
render (){
const {errors,country,city,category} = this.state;
return(
<section className="Hosteldashboard">
<div className="left_container">
<h2>Yo che left section</h2>
<div>
<form noValidate onSubmit={this.addOption}>
<div class="form-row">
<label htmlFor="country">Country</label> <br />
<input
type="text"
className="input-control"
placeholder="Country name"
id="country"
value={country}
onChange={this.onChangeAddOptions}
error={errors.country}
className={classnames('', {
invalid: errors.country
})}
/>{' '}
<br />
<span className="text-danger">{errors.country}</span>
</div>
<div class="form-row">
<label htmlFor="city">City</label> <br />
<input
type="text"
className="input-control"
placeholder="City name"
id="city"
value={city}
onChange={this.onChangeAddOptions}
error={errors.city}
className={classnames('', {
invalid: errors.city
})}
/>{' '}
<br />
<span className="text-danger">{errors.city}</span>
</div>
<div class="form-row">
<label htmlFor="category">Category</label> <br />
<input
type="text"
className="input-control"
placeholder="Boys or Girls"
id="category"
value={category}
onChange={this.onChangeAddOptions}
error={errors.category}
className={classnames('', {
invalid: errors.category
})}
/>{' '}
<br />
<span className="text-danger">{errors.category}</span>
</div>
<div>
<button type="submit" className = "searchHostel" onClick={this.getHostels}>
Search
</button>
</div>
</form>
</div>
</div>
In backend :
router.post('/hostel',async (req,res)=>{
try{
console.log(req.body);
const {
errors,
isValid
} = validateSearchHostelInput(req.body);
//Check Validation
// if (!isValid){
// return res.status(400).json(errors);
// }
const page = parseInt(req.query.page) - 1 || 0;
const limit = parseInt(req.query.limit) || 5;
const search = req.query.search || "";
let sort = req.query.sort || "price";
let category = req.query.category || "All";
const categoryOptions = [
req.body.country,
req.body.city,
req.body.category
]
category === "All"
? (category = [...categoryOptions])
: (category = req.query.category.split(","));
req.query.sort ? (sort = req.query.sort.split(",")) : (sort = [sort]);
let sortBy = {};
if(sort[1]) {
sortBy[sort[0]] = sort[1];
} else {
sortBy[sort[0]] = "asc";
}
const hostel = await Hostel.find({title: {$regex: search, $options: "i"}})
.where("category")
.in([...category])
.sort(sortBy)
.skip(page * limit)
.limit(limit);
// const total = await Hostel.countDocuments({
// category: {$in: [...category]},
// title: { $regex: search, $options: "i"},
// });
// const response = {
// error: false,
// total,
// page: page + 1,
// limit,
// categories: categoryOptions,
// hostel
//}
console.log("From Hostel : " + hostel);
res.status(200).json({hostel:hostel});
}catch(err){
console.log(err);
res.status(500).json({error:true,message:"Internal Server Error"});
}
});
module.exports = router;

Related

Warning: Each child in a list should have a unique "key" prop and does not save in my json-server

I keep getting error "Warning: Each child in a list should have a unique "key" prop" on console log. I think there is something wrong in the
axios.delete('http://localhost:3000/contacts/${id}
' or
axios.put('http://localhost:3000/contacts/${isUpdate.id}'
It works, but does not configure in the json-server that I made. So the changes does not happen in the json-server.
The "save" button works, and added new data into my json-server. But, when I tried to edit, or delete, it does not save the changed in json-server.
My code:
import "./App.css";
import List from "./List";
import { useState,useEffect } from "react";
import {uid} from "uid";
import axios from "axios";
function App() {
const [contacts, setContacts] = useState([]);
function handleChange(e) {
let data = { ...formData };
data[e.target.name] = e.target.value;
setFormData(data);
}
const [isUpdate, setIsUpdate] = useState({ id: null, status: false});
const [formData, setFormData] = useState({
name: "",
telp: "",
});
useEffect(() => {
axios.get("http://localhost:3000/contacts").then((res) => {
console.log(res.data);
setContacts(res?.data ?? []);
});
}, []);
function handleSubmit(e){
e.preventDefault();
alert("Oke Bos!");
let data = [...contacts];
if(formData.name === "") {
return false;
}
if(formData.telp === "") {
return false;
}
if ( isUpdate.status){
data.forEach((contact) => {
if (contact.id === isUpdate.id) {
contact.name = formData.name;
contact.telp = formData.telp;
}
});
axios.put('http://localhost:3000/contacts/${isUpdate.id}', {
name: formData.name,
telp: formData.telp,
})
.then((res) => {
alert("Berhasil edit data!");
});
} else {
let newData = { id: uid(), name: formData.name, telp: formData.telp };
data.push(newData);
axios.post("http://localhost:3000/contacts", newData).then((res) => {
alert("Data telah disimpan cok!");
});
}
// tambah kontak yee
setIsUpdate({id: null, status: false});
setContacts(data);
setFormData({ name: "", telp: ""});
}
function handleEdit(id) {
let data = [...contacts];
let foundData = data.find((contact) => contact.id === id);
setFormData({ name: foundData.name, telp: foundData.telp});
setIsUpdate({id: id, status: true});
}
function handleDelete(id) {
let data = [...contacts];
let filteredData = data.filter((contact) => contact.id !== id);
axios.delete('http://localhost:3000/contacts/${id}').then((res) => {
alert("Data telah dihapus");
});
setContacts(filteredData);
}
return (
<div className="App">
<h1 className="px-3 py-3">My Contact List</h1>
<form onSubmit={handleSubmit} className="px-3 py-4">
<div className="form-group">
<label htmlFor="">Name</label>
<input type="text"
className="form-control"
onChange={handleChange}
value={formData.name}
name="name" />
</div>
<div className="form-group mt-3">
<label htmlFor="">No. Telp</label>
<input type="text"
className="form-control"
onChange={handleChange}
value={formData.telp}
name="telp" />
</div>
<div>
<button type="submit" className="btn btn-primary w-100 mt-3">
Save
</button>
</div>
</form>
<List handleDelete={handleDelete} handleEdit={handleEdit} data={contacts} />
</div>
);
}
export default App;
The list component:
import React from "react";
export default function List({data,handleEdit,handleDelete}) {
return (
<div className="list-group">
{
data.map((contact) => {
return (
<div className="list-group-item list-group-item-action">
<div className="d-flex w-100 justify-content-between">
<h5 className="mb-1">{contact.name}</h5>
<div>
<button onClick={() => handleEdit(contact.id)} className="btn btn-sm btn-link">Edit</button>
<button onClick={() => handleDelete(contact.id)} className="btn btn-sm btn-link">Del</button>
</div>
</div>
<p className="mb-1">{contact.telp}</p>
</div>
);
})}
</div>
);
}
I follow the tutorial, the code is like this, i checked it in so many times. But still it does not configure well into json-server like what i see on youtube.

How to send formData that includes image

I'm trying to send my form using React frontend to NodeJS backend and I'm not getting any data in formData() object, here is my code for React:
import { useState, useEffect } from 'react'
import Axios from 'axios'
import Notification from '../../../components/Notification'
const DashboardWorkAdd = ({ subTitle = 'works' }) => {
//Form States
const [workName, setWorkName] = useState('')
const [workGithub, setWorkGithub] = useState('')
const [workOnlineLink, setWorkOnlineLink] = useState('')
const [workDate, setWorkDate] = useState('')
const [workDesc, setWorkDesc] = useState('')
const [workAdded, setworkAdded] = useState('')
const [workAddedMsg, setworkAddedMsg] = useState('')
const [workImgFile, setWorkImgFile] = useState('')
const [preview, setPreview] = useState()
const formMsg = document.querySelector('.notification__msg')
const updateWorkImg = (e) => {
const file = e.target.files[0]
if (file) {
const fileType = file.type.split('/')[0]
const fileSizeToMB = file.size / 1000000
const MAX_FILE_SIZE = 1 //mb
if (formMsg) {
formMsg.classList.remove('hidden')
if (fileType !== 'image') {
formMsg.textContent = 'you can add only image file'
} else if (fileSizeToMB > MAX_FILE_SIZE) {
formMsg.textContent = `you can't add more than ${MAX_FILE_SIZE} MB`
return
} else {
formMsg.classList.add('hidden')
formMsg.textContent = ''
setWorkImgFile(file)
}
}
}
}
useEffect(() => {
// if there's an image
if (workImgFile) {
const reader = new FileReader()
reader.onloadend = () => setPreview(reader.result)
reader.readAsDataURL(workImgFile)
} else {
setPreview(null)
}
}, [workImgFile])
const handleAddWork = async (e) => {
e.preventDefault()
//using FormData to send constructed data
const formData = new FormData()
formData.append('workImg', workImgFile)
formData.append('workName', workName)
formData.append('workGithub', workGithub)
formData.append('workOnlineLink', workOnlineLink)
formData.append('workDate', workDate)
formData.append('workDesc', workDesc)
console.log(formData)
if (
(workName === '' || workGithub === '' || workOnlineLink === '' || workDate === '',
workDesc === '')
) {
formMsg.textContent = 'please add all data'
} else {
try {
const response = await Axios.post(
`${
process.env.NODE_ENV === 'development'
? process.env.REACT_APP_API_LOCAL_URL
: process.env.REACT_APP_API_URL
}/workAdd`,
{ workImgFile, workName, workGithub, workOnlineLink, workDate, workDesc }
)
const { workAdded, message } = response.data
setworkAdded(workAdded)
setworkAddedMsg(message)
} catch (err) {
console.error(err)
}
}
}
return (
<>
<h3 className='text-3xl mt-20 mb-12 text-center font-semibold'>{subTitle}</h3>
<div className='h-full'>
<div className='flex flex-col gap-3 py-4 text-sm font-semibold'>
<Notification sendStatus={workAdded} sendStatusMsg={workAddedMsg} />
<div className='notification__msg'></div>
<form
method='POST'
className='flex flex-col gap-14'
encType='multipart/form-data'
onSubmit={handleAddWork}
>
<label
htmlFor='workImg'
className='flex flex-wrap justify-center gap-5 md:justify-between items-center cursor-pointer'
>
<img
src={
preview === null ? 'https://source.unsplash.com/random?webdev' : preview
}
alt='Work Portfolio Preview'
className='w-36 h-36'
/>
<input
type='file'
name='workImg'
id='workImg'
className='bg-blue-500 py-6 px-28 rounded-lg text-white uppercase font-semibold cursor-pointer'
accept='image/*'
onChange={updateWorkImg}
multiple
required
/>
</label>
<div className='dashboard-group'>
<label htmlFor='workName'>work name</label>
<input
type='text'
id='workName'
autoFocus
onChange={(e) => {
setWorkName(e.target.value.trim())
}}
required
/>
</div>
<div className='dashboard-group'>
<label htmlFor='workLinkGithub'>Github Link</label>
<input
type='text'
id='workLinkGithub'
min='5'
max='500'
onChange={(e) => setWorkGithub(e.target.value.trim())}
required
/>
</div>
<div className='dashboard-group'>
<label htmlFor='workLinkOnline'>Online Linl</label>
<input
type='text'
id='workLinkOnline'
min='5'
max='500'
onChange={(e) => setWorkOnlineLink(e.target.value.trim())}
required
/>
</div>
<div className='dashboard-group'>
<label htmlFor='workDate'>Work Date</label>
<input
type='date'
id='workDate'
min='5'
max='500'
onChange={(e) => setWorkDate(e.target.value.trim())}
required
/>
</div>
<div className='dashboard-group'>
<label htmlFor='workDescription'>word description</label>
<textarea
name='workDescription'
id='workDescription'
minLength='10'
maxLength='300'
className=''
onChange={(e) => setWorkDesc(e.target.value.trim())}
required
></textarea>
</div>
<div className='flex justify-around text-lg'>
<button
type='submit'
className='bg-green-500 hover:bg-green-600 py-2 px-20 rounded-lg text-white transition-colors'
>
Add
</button>
</div>
</form>
</div>
</div>
</>
)
}
export default DashboardWorkAdd
Here is my code for NodeJS:
const WorksModel = require('../models/WorkModel')
const { v4: uuidv4 } = require('uuid')
module.exports = async (req, res) => {
const { workName, workGithub, workOnlineLink, workDate, workDesc } = req.body
const { workImg } = req.files
const workImgName = uuidv4() + workImg.name
const workImgMovePath = `${__dirname}/../../client/public/uploads/${workImgName}`
const workImgDisplayPath = `/uploads/${workImgName}`
const works = new WorksModel({
workImgDisplayPath,
workName,
workGithub,
workOnlineLink,
workDate,
workDesc
})
try {
await works.save()
workImg.mv(workImgMovePath, (err) => {
if (err) {
res.send({ message: `sorry, something wrong with the server: ${error}` })
return res.status(500).send(err)
}
})
res.send({
message: 'added succesfully',
workAdded: 1
})
} catch (error) {
res.send({
message: `something went wrong ${error}`,
workAdded: 0
})
}
}
and my WorkModel file is :
const mongoose = require('mongoose')
const WorkSchema = new mongoose.Schema({
workImgDisplayPath: {
type: String,
required: true
},
workName: {
type: String,
required: true
},
workGithub: {
type: String,
required: true
},
workOnlineLink: {
type: String,
required: true
},
workDate: {
type: Date,
required: true,
default: new Date().toLocaleDateString('ar-EG', {
weekday: 'long',
year: 'numeric',
month: 'short',
day: 'numeric'
})
},
workDesc: {
type: String,
required: true
}
})
const WorkModel = mongoose.model('mhmdhidrPortfolio', WorkSchema)
module.exports = WorkModel
the issue I'm having when I get the data in the backend is the req.files are undefined, I googled a lot and I don't know the issue exactly.
Thanks for your help.
I solved my problem, I just had to add:
const fileUpload = require('express-fileupload')
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(fileUpload())
inside my index.js (server) file

Unexpected token " in JSON at position 0

My Goal for this one is to Add ObjectId inside the array
In my backend Im declare schema on this code:
tchStudents: [{
type: Schema.Types.ObjectId,
ref: "Student"
}]
THen Im do adding an ObjectId to insert to the array of ObjectID:
My BackEnd is very fine
router.put('/assignAddStudents/:tchID', async (req,res) => {
try {
const searchTch = await Teacher.findOne({ tchID: req.params.tchID })
if(!searchTch){
return res.status(404).send({
success: false,
error: 'Teacher ID not found'
});
} else {
let query = { tchID: req.params.tchID }
let assignedStudentObjID = {$push:{tchStudents: req.body.tchStudents }}
Teacher.updateOne(query, assignedStudentObjID ,() => {
try{
return res.status(200).send({
success: true,
msg: 'Student ID has been assigned'
});
} catch(err) {
console.log(err);
return res.status(404).send({
success: false,
error: 'Teacher ID not found'
})
}
})
}
} catch (err) {
console.log(err)
}
})
But my Front End Not working
err: BAD REQUEST(400) Unexpected token " in JSON at position 0
import React, {useState} from 'react'
import axios from 'axios'
import { URL } from '../../utils/utils'
import { Modal, Button } from 'react-materialize';
import ListTchStudents from '../lists/ListTchStudents';
const trigger =
<Button
style={{marginLeft:'2rem'}}
tooltip="Add More..."
tooltipOptions={{
position: 'top'
}}
className="btn-small red darken-4">
<i className="material-icons center ">add_box</i>
</Button>;
const MdlAddStudents =({teacher}) => {
const [data, setData] = useState('');
const { tchStudents} = data;
const {
tchID,
} = teacher; // IF WE RENDER THIS IT TURNS INTO OBJECT
const assignedStudent = () => {
// BUT WE SENT IT TO THE DATABASE CONVERT TO JSON.STRINGIFY to make ObjectId
const requestOpt = {
method: 'PUT',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify(data)
}
axios.put(`${URL}teachers/assignAddStudents/${tchID}`, data,requestOpt)
.then(res => {
setData(res.data.data)
})
}
return (
<Modal header="Add Students" trigger={trigger}>
Please ADD and REMOVE Student ID No. for {tchID}
<div>
<ul
style={{marginBottom:'2rem'}}
className="collection">
{
Object.values(teacher.tchStudents).map(tchStudent => {
return(
<ListTchStudents
tchStudent={tchStudent}
/>
);
})
}
</ul>
<div className="row">
<div className="col s6 offset-s3"></div>
<div className="input-field">
<label
htmlFor=""
className="active black-text"
style={{fontSize:'1.3rem'}}>
Add Students here:
</label>
<input
type="text"
name="tchStudents"
value={(tchStudents)}
className="validate"
onChange={(e) => setData(e.target.value)}
/>
</div>
</div>
</div>
{/* BUT WE SENT IT TO THE DATABASE CONVERT TO JSON.STRINGIFY to send ObjectId to the database
*/}
<div className="row">
<div className="col s2 offset-s3" ></div>
<Button
onClick={assignedStudent}
tooltip="Add Students"
tooltipOptions={{
position: 'right'
}}
className="btn green darken-3">
<i className="material-icons ">add_circle</i>
</Button>
</div>
<p>There are {Object.values(teacher.tchStudents).length} student/s
assigned</p>
</Modal>
)
}
// MdlAddStudents.propTypes = {
// assignedStudents: PropTypes.func.isRequired,
// }
export default MdlAddStudents;
// export default connect(null, (assignedStudents))(MdlAddStudents);
Thank you for helping out
The problem stems from you attempting to wrap your tchStudents state property in an object named data.
My advice is to keep it very simple
// it's just a string
const [tchStudents, setTchStudents] = useState("")
const assignedStudent = () => {
// create your request payload
const data = { tchStudents }
// no config object required
axios.put(`${URL}teachers/assignAddStudents/${tchID}`, data)
.then(res => {
// not sure what you want to do here exactly but
// `res.data` should look like
// { success: true, msg: 'Student ID has been assigned' }
setTchStudents("") // clear the input ¯\_(ツ)_/¯
})
}
The only other change is to use the new setter name in your <input>...
<input
type="text"
name="tchStudents"
value={tchStudents}
className="validate"
onChange={(e) => setTchStudents(e.target.value)}
/>

Unable to fetch data from Form using FormData

I am creating an 'edit profile' page for a dashboard the technologies that I use for the same are Next.js, Node.js & MongoDB.
Note: skip to the backend part if you just wanted to know the issue.
Frontend
Firstly,let me explain the Frontend part.
I am using useRef() inorder to reference data(name,bio) in the inputfields. which are working nicely.
Everything is fine the issue is in the handlesbumit() event_handler.
I am using FormData to send my form data to the backend API
If you're thinking why I'm not using a usual body object to send data the reason is that I have to add the profile picture updation later for which I have to send files , which as far I know we can't do that with an Object and yeah just to inform you it works fine if I would have used that Object part but can't use it with profilepicture updation.
The value that I have consoled out for the references are all good, and the rest of the handler is just as it is written can't find anything odd in that.
import { useUser } from '../../../lib/hooks';
import React, { useState, useEffect, useRef } from 'react';
import Head from 'next/head';
import { ImBook, ImListNumbered } from 'react-icons/im';
import { AiFillGithub, AiOutlineTwitter, AiFillFacebook, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'
import { FaFacebook, FaStackOverflow } from 'react-icons/fa';
const ProfileSection = () => {
const [user, { mutate }] = useUser();
const [isUpdating, setIsUpdating] = useState(false);
const nameRef = useRef();
const profilePictureRef = useRef();
const bioRef = useRef();
const [msg, setMsg] = useState({ message: '', isError: false });
useEffect(() => {
nameRef.current.value = user.name;
bioRef.current.value = user.Bio;
}, [user]);
const handleSubmit = async (event) => {
event.preventDefault();
if (isUpdating) return;
setIsUpdating(true);
console.log(nameRef.current.value); //Testing
console.log(bioRef.current.value); //Testing
const formData = new FormData();
formData.append('name', nameRef.current.value);
formData.append('Bio', bioRef.current.value);
console.log(formData.get('name'));
const res = await fetch('/api/user', {
method: 'PATCH',
body: formData,
});
if (res.status === 200) {
const userData = await res.json();
mutate({
user: {
...user,
...userData.user,
},
});
setMsg({ message: 'Profile updated' });
} else {
setMsg({ message: await res.text(), isError: true });
}
};
return (
<>
<Head>
<title>Settings</title>
</Head>
<main>
<div class="row">
<div class="col s12 m12">
<div className="card-panel br-10">
{msg.message ? <p style={{ color: msg.isError ? 'red' : '#0070f3', textAlign: 'center' }}>{msg.message}</p> : null}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col s12 m6 l6">
<label htmlFor="name">
Name
<input
required
id="name"
name="name"
type="text"
ref={nameRef}
/>
</label>
</div>
<div className="col s12 m6 l6">
<label htmlFor="bio">
Bio
<textarea
id="bio"
name="bio"
type="text"
ref={bioRef}
/>
</label>
</div>
</div>
<div className="center-align">
<button disabled={isUpdating} className="btn" type="submit" >Save</button>
</div>
</form>
</div>
</div>
</div>
</main>
</>
);
};
const SettingPage = () => {
const [user] = useUser();
if (!user) {
return (
<>
<p>Please sign in</p>
</>
);
}
return (
<>
<ProfileSection />
</>
);
};
export default SettingPage;
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import { useUser } from '../../../lib/hooks';
import React, { useState, useEffect, useRef } from 'react';
import Head from 'next/head';
import { ImBook, ImListNumbered } from 'react-icons/im';
import { AiFillGithub, AiOutlineTwitter, AiFillFacebook, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'
import { FaFacebook, FaStackOverflow } from 'react-icons/fa';
const ProfileSection = () => {
const [user, { mutate }] = useUser();
const [isUpdating, setIsUpdating] = useState(false);
const nameRef = useRef();
const profilePictureRef = useRef();
const bioRef = useRef();
const [msg, setMsg] = useState({ message: '', isError: false });
useEffect(() => {
nameRef.current.value = user.name;
bioRef.current.value = user.Bio;
}, [user]);
const handleSubmit = async (event) => {
event.preventDefault();
if (isUpdating) return;
setIsUpdating(true);
console.log(nameRef.current.value);
console.log(bioRef.current.value);
const formData = new FormData();
formData.append('name', nameRef.current.value);
formData.append('Bio', bioRef.current.value);
console.log(formData.get('name'));
const res = await fetch('/api/user', {
method: 'PATCH',
body: formData,
});
if (res.status === 200) {
const userData = await res.json();
mutate({
user: {
...user,
...userData.user,
},
});
setMsg({ message: 'Profile updated' });
} else {
setMsg({ message: await res.text(), isError: true });
}
};
return (
<>
<Head>
<title>Settings</title>
</Head>
<main>
<div class="row">
<div class="col s12 m12">
<div className="card-panel br-10">
{msg.message ? <p style={{ color: msg.isError ? 'red' : '#0070f3', textAlign: 'center' }}>{msg.message}</p> : null}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col s12 m6 l6">
<label htmlFor="name">
Name
<input
required
id="name"
name="name"
type="text"
ref={nameRef}
/>
</label>
</div>
<div className="col s12 m6 l6">
<label htmlFor="bio">
Bio
<textarea
id="bio"
name="bio"
type="text"
ref={bioRef}
/>
</label>
</div>
</div>
<div className="center-align">
<button disabled={isUpdating} className="btn" type="submit" >Save</button>
</div>
</form>
</div>
</div>
</div>
</main>
</>
);
};
const SettingPage = () => {
const [user] = useUser();
if (!user) {
return (
<>
<p>Please sign in</p>
</>
);
}
return (
<>
<ProfileSection />
</>
);
};
export default SettingPage;
Backend
Now, the backend API for the same handlesubmit() event_handler i.e. 'api/user'
Please ignore the handler, it's just a predefined middleware npm next-connect which itself checks what type of request is coming if its 'PATCH' it will run handler.patch.
The Issue is the value of name & Bio is undefined,which means its not getting values from req.body;
And to check I also consoled out req.body which give out this
The data is correct but req.body is not a Object its a String now and I get it, its because I'm using formdata so how to get the values of name & Bio from this req.body ?
import nextConnect from 'next-connect';
import middleware from '../../../middlewares/middleware';
import { extractUser } from '../../../lib/api-helpers';
const handler = nextConnect();
handler.use(middleware);
handler.get(async (req, res) => res.json({ user: extractUser(req) }));
handler.patch(async (req, res) => {
if (!req.user) {
req.status(401).end();
return;
}
const { name, Bio } = req.body;
await req.db.collection('users').updateOne(
{ _id: req.user._id },
{
$set: {
name:name,
Bio: Bio,
},
},
);
res.json({ user: { name, Bio } });
});
export default handler;
I have encountered a this issue.
I was resolve it by use 2 form, a form use to get user's info as email, password and the other for send user's picture.
Maybe has best practice for this case.

ReactJS: adding spinner/progress bar to the page

I have no luck with adding spinner/progress bar to the page.
Tried many different libraries , without no success.
I need it to show on
//SHOW SPINNER
and then hide on
//HIDE SPINNER
line in the bellow code
Any help appreciated.
import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import { deleteUser } from '../actions/Actions';
import { updateUser as APIUpdateUser, addUser as APIAddUser } from '../utils/APIUtils';
import language from '../language';
import scrollToElement from 'scroll-to-element';
import CarsSelect from './CarsSelect';
var _ = require('lodash');
function mapStateToProps(state) {
return {
};
}
class UserTableRow extends Component {
static propTypes = {
data: PropTypes.object.isRequired,
number: PropTypes.number.isRequired,
}
static contextTypes = {
store: React.PropTypes.object
}
constructor(props) {
console.log("Progress");
super(props);
this.state = {
edit: false,
data: props.data
};
this._handleChange = this._handleChange.bind(this);
this._handleCarChange = this._handleCarChange.bind(this);
this._startEdit = this._startEdit.bind(this);
this._cancelEdit = this._cancelEdit.bind(this);
this._handleSave = this._handleSave.bind(this);
this._handleShow = this._handleShow.bind(this);
}
componentDidMount() {
const {data} = this.props;
if (typeof data.new !== 'undefined' && data.new === true) {
this.setState({
edit: true
});
scrollToElement(this.refs.row, {
offset: 0,
ease: 'out-bounce',
duration: 1000
});
}
}
componentWillReceiveProps(nextProps) {
this.setState({
data: nextProps.data,
});
}
render() {
const {number} = this.props;
const {data} = this.state;
const lang = language[language.default];
var showClass = 'more';
var rowHidden = 'hidden';
if (this.state.more === true) {
showClass = 'less';
rowHidden = 'visible';
}
var editClass = '';
if (this.state.edit === true) {
editClass = 'table__row--edit';
}
return (
<div>
<div ref='row' className={'table__row table__row--outer ' + editClass}>
<div className='table__elements-wrapper'>
<div className='table__element'>{number}</div>
<div className='table__element'>
<span className='table__editable-data'>{data.email}</span>
<input onChange={this._handleChange.bind(this, 'email')} className='table__editable-hidden' ref='email' name='email' type='email' value={data.email} />
</div>
<div className='table__element'>
<span className='table__editable-data'>{data.firstName}</span>
<input onChange={this._handleChange.bind(this, 'firstName')} className='table__editable-hidden' ref='firstName' name='firstName' type='text' value={data.firstName} />
</div>
<div className='table__element'>
<span className='table__editable-data'>{data.lastName}</span>
<input onChange={this._handleChange.bind(this, 'lastName')} className='table__editable-hidden' ref='lastName' name='lastName' type='text' value={data.lastName} />
</div>
<div className='table__element'>
<span className='table__editable-data'>{data.phone}</span>
<input onChange={this._handleChange.bind(this, 'phone')} className='table__editable-hidden' ref='phone' name='phone' type='text' value={data.phone} />
</div>
<div className='table__element'>
<span className='table__editable-data'>{lang.userArr[data.type]}</span>
<select onChange={this._handleChange.bind(this, 'type')} className='table__editable-hidden' ref='type' name='type' type='text' value={data.type}>
<option value='0'>{lang.userArr[0]}</option>
<option value='1'>{lang.userArr[1]}</option>
<option value='2'>{lang.userArr[2]}</option>
</select>
</div>
<div className='table__element'>
<input className='table__editable-hidden' ref='password' name='password' type='password' />
</div>
<div className='table__element table__element--avatar'>
<img lightbox='lightbox' className='table__editable-data' src={data.image} alt=''/>
<input className='table__editable-hidden' type='file' ref='image' name='image' />
</div>
<div className='table__element'>
{(() => {
if (data.superAdmin !== true) {
return <div className='table__buttons'>
<div onClick={this._startEdit} className='table__button table__button--edit'></div>
<div onClick={this._cancelEdit} className='table__button table__button--cancel '></div>
<div onClick={this._handleSave} className='table__button table__button--ok'></div>
</div>;
} else {
return false;
}
})()}
</div>
<div className='table__element'><div onClick={this._handleShow} className={'table__show table__show--' + showClass}></div></div>
</div>
<div ref='hiddenRow' className={'table__row table__row--inner table__row--' + rowHidden}></div>
</div>
</div>
);
}
_handleShow() {
var more = this.state.more;
if (!more) {
ReactDOM.render(<CarsSelect handleCarChange={this._handleCarChange} user={this.state.data} />, this.refs.hiddenRow);
} else {
ReactDOM.unmountComponentAtNode(this.refs.hiddenRow);
}
this.setState({
more: !more
});
}
_handleCarChange(e) {
var {data} = this.state;
var values = [];
var userValues = [];
_.each(e, function(item) {
values.push({nameplate: item.label, _id: item.value});
userValues.push(item.value);
});
data.cars = values;
this.setState({
data: data
});
var user = {};
user._id = data._id;
user.cars = userValues;
APIUpdateUser(user);
}
_handleChange(type, event) {
var data = this.state.data;
data[type] = event.target.value;
this.setState({
data: data
});
}
_startEdit() {
this.setState({
edit: true
});
}
_cancelEdit() {
const {data} = this.props;
if (data.new === true) {
this.context.store.dispatch(deleteUser(data));
}
this.setState({
edit: false
});
}
_handleSave() {
//SHOW SPINNER
const {data} = this.props;
var user = {};
user._id = data._id;
user.email = this.refs.email.value;
user.firstName = this.refs.firstName.value;
user.lastName = this.refs.lastName.value;
user.phone = this.refs.phone.value;
user.type = this.refs.type.value;
if (this.refs.password.value) {
user.password = this.refs.password.value;
}
if (this.refs.image.files[0]) {
var reader = new window.FileReader();
reader.readAsDataURL(this.refs.image.files[0]);
reader.onloadend = function() {
user.image = reader.result;
console.log(user.image);
if (data.new === true) {
this.context.store.dispatch(deleteUser(data));
APIAddUser(user);
} else {
APIUpdateUser(user);
}
};
} else {
if (data.new === true) {
this.context.store.dispatch(deleteUser(data));
APIAddUser(user);
} else {
APIUpdateUser(user);
}
}
this.setState({
edit: false
});
//HIDE SPINNER
}
}
var getOptions = function(input, callback) {
setTimeout(function() {
callback(null, {
options: [
{value: 'one', label: 'One'},
{value: 'two', label: 'Two'}
],
// CAREFUL! Only set this to true when there are no more options,
// or more specific queries will not be sent to the server.
complete: true
});
}, 500);
};
export default connect(mapStateToProps)(UserTableRow);
Install
$ npm install react-spinkit --save
Usage
import Spinner from 'react-spinkit';
<Spinner spinnerName='double-bounce' />
see more here https://github.com/KyleAMathews/react-spinkit

Resources