MERN stack: Cast to Number failed for value 'NaN' - node.js

I'm creating a simple user registration page where account level (1 = user & 2= admin) is putting up an error when i post a request through axios. This seemed to be a somewhat common error corrected mostly by having a default number value in the schema, which I already have. Furthermore, I do not come across this error when I test with postman.
Error:
Error: users validation failed: accLevel: Cast to Number failed for value "NaN" (type number) at path "accLevel", username: Path `username` is required., password: Path `password` is required.
at ValidationError.inspect (E:\SLIIT\Y2S2\ITP\FitnessFactory\backend\node_modules\mongoose\lib\error\validation.js:48:26)
However, when I test with post man I do not get this error and mongodb works. Like so. It also works for accLevel in int form.
{
"username": "Mary",
"password": "mary",
"accType": "customer",
"accLevel": "1"
}
Heres the user schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
username : {
type: String,
required: true
},
password : {
type: String,
required: true
},
accType: {
enum: ["customer", "instructor"],
//required: true
},
accLevel: {
type: Number,
default: 1
}
})
const User = mongoose.model('users', userSchema);
module.exports = User;
Heres the user route and controller file
const router = require("express").Router();
let User = require("../models/user");
//createUserAccount
router.route("/createUserAccount").post((req,res) => {
const username = req.body.username;
const password = req.body.password;
const accType = req.body.accType;
const accLevel = Number(req.body.accLevel);
const newUser = new User({
username,
password,
accType,
accLevel
})
newUser.save().then(() => {
res.json("User account created")
}).catch((err) => {
console.log(err);
})
})
//login
router.route("/userLogin/:id").post(async(req,res) => {
})
module.exports = router;
Heres is the component file for createUserAccount.jsx
//Create account component
import React, {useState} from "react";
import axios from 'axios';
//bootstrap imports
import Form from 'react-bootstrap/Form';
import Button from "react-bootstrap/Button";
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
//custom styles
import '../styles/CreateAccount.css';
function CreateAccount(){
//set states
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [reEnterPassword, setReEnterPassword] = useState("");
const [accType, setAccType] = useState("");
const [accLevel, setAccLevel] = useState("");
//handle change
function handleSubmit(e){
e.preventDefault();
if (password !== reEnterPassword){
alert("Passwords do not match!")
}
else if (accType === ''){
alert("Select account type!")
}
else if (accLevel === ''){
alert("Select account level!")
}
else{
const newUser = {
username,
password,
accType,
accLevel
}
console.log(newUser);
axios.post("http://localhost:8070/user/createUserAccount").then(()=>{
alert("account created")
}).catch((err)=>{
alert(err)
})
}
}
return (
<div>
<div className='createAccountBlock'>
<h1>Create Account</h1>
<form onSubmit={handleSubmit}>
<Form.Group name="username" className="mb-3" controlId="username">
<Form.Label>Username</Form.Label>
<Form.Control type="text" placeholder="Enter Username" className='formText'
onChange = {(e)=>{
setUsername(e.target.value);
}}
/>
</Form.Group>
<Form.Group name="password" className="mb-3" controlId="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" className='formText'
onChange = {(e)=>{
setPassword(e.target.value);
}}
/>
</Form.Group>
<Form.Group name="reEnterPassword" className="mb-3" controlId="reEnterPassword">
<Form.Label>Re-enter Password</Form.Label>
<Form.Control type="password" placeholder="Re-enter Password" className='formText'
onChange = {(e)=>{
setReEnterPassword(e.target.value);
}}
/>
</Form.Group>
<Container>
<Row>
<Col>
<Form.Select name="accType" aria-label="Default select example"
onChange = {(e)=>{
setAccType(e.target.value);
}}
>
<option>Select Account Type</option>
<option value="customer">Customer</option>
<option value="instructor">Instructor</option>
</Form.Select>
</Col>
<Col>
<Form.Select name="accLevel" aria-label="Default select example"
onChange = {(e)=>{
setAccLevel(e.target.value);
}}
>
<option>Select Account Level</option>
<option value="1">Level 1 (user)</option>
<option value="2">Level 2 (admin)</option>
</Form.Select>
</Col>
</Row>
<div className='flex-container'>
<Button variant="primary" type="submit" className='btn1'>
Create Account
</Button>
</div>
</Container>
</form>
</div>
</div>
);
}
export default CreateAccount;
It works when I test with postman for both int and string, but fails using axios. Btw, I tried parseInt from the frontend as well.
Any Ideas?

It doesn't look like you're sending a data object in your POST request.
axios.post("http://localhost:8070/user/createUserAccount").then(()=>{
alert("account created")
}).catch((err)=>{
alert(err)
})
axios.post needs a second argument of the object that you are sending.

Related

GraphQL + ReactJS throws Error 400: Bad Request

I've been stuck at trying to submit my form for a couple of days now. I constantly get hit with the following error: "POST http://localhost:5000/graphql 400 (Bad Request)".
I believe the problem lies somewhere within the mutation/query itself and not the headers since the request is sent in the correct content type (application/json) as you can see in the screenshot.
My code (warning, I'm an absolute beginner) is the following:
// #flow
import React, { useState } from 'react';
import { Row, Col, Card, OverlayTrigger, Tooltip } from 'react-bootstrap';
import { FormInput } from '../../../../components';
type ChecklistsItems = {
id: number,
title: string,
completed: boolean,
};
type AttachmentsItems = {
id: number,
filename: string,
size: string,
};
type CommentsItems = {
id: number,
author: string,
text: string,
posted_on: string,
author_avatar: string,
};
type TaskProps = {
id: number,
title: string,
assigned_to: string,
assignee_avatar: string,
due_date: string,
completed: boolean,
priority: string,
stage: string,
checklists: Array<ChecklistsItems>,
description: string,
attachments: Array<AttachmentsItems>,
comments: Array<CommentsItems>,
};
const createMarkup = (text) => {
return { __html: text };
};
const Task = (task: TaskProps): React$Element<React$FragmentType> => {
const [completed, setCompleted] = useState(task.completed == true);
const [enteredTitle, setEnteredTitle] = useState('');
const [enteredPriority, setEnteredPriority] = useState('');
const [enteredDescription, setEnteredDescription] = useState('');
const [enteredDeadline, setEnteredDeadline] = useState('');
const [enteredStartTime ,setEnteredStartTime] = useState('');
const [enteredEndTime, setEnteredEndTime] = useState('');
const [enteredColor, setEnteredColor] = useState('');
/*
* mark completd on selected task
*/
const markCompleted = (e) => setCompleted(e.target.checked);
const titleChangeHandler = (event) => {
setEnteredTitle(event.target.value);
};
const priorityChangeHandler = (event) => {
setEnteredPriority(event.target.value);
};
const descriptionChangeHandler = (event) => {
setEnteredDescription(event.target.value)
};
const deadlineChangeHandler = (event) => {
setEnteredDeadline(event.target.value)
}
const startTimeChangeHandler = (event) => {
setEnteredStartTime(event.target.value);
}
const endTimeChangeHandler = (event) => {
setEnteredEndTime(event.target.value);
}
const colorChangeHandler = (event) => {
setEnteredColor(event.target.value);
}
const submitHandler = (event) => {
event.preventDefault();
const taskData = {
title: enteredTitle,
priority: enteredPriority,
description: enteredDescription,
due_date: new Date(enteredDeadline),
start: new Date(enteredStartTime),
end: new Date(enteredEndTime),
color: enteredColor,
};
console.log(taskData);
setEnteredTitle('');
setEnteredPriority('');
setEnteredDescription('');
setEnteredDeadline('');
setEnteredStartTime('');
setEnteredEndTime('');
setEnteredColor('#');
const requestBody = {
query: `
mutation {
createTask(taskInput: {title: "${enteredTitle}", description: "${enteredPriority}", priority: "${enteredDescription}", due_date: "${enteredDeadline}", start: "${enteredStartTime}", end: "${enteredEndTime}", color: "${enteredColor}"} ) {
_id
title
description
priority
due_date
start
end
color
creator {
id
email
}
}
}
`
};
fetch('http://localhost:5000/graphql', {
method: 'POST',
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if (res.status !== 200 && res.status !== 201) {
throw new Error('Failed!');
}
return res.json();
})
.then(resData => {
this.fetchTasks();
})
.catch(err => {
console.log(err);
});
};
return (
<React.Fragment>
<div style={{marginTop:'118px'}} />
<Card >
<Card.Body>
<h3>Add Task</h3>
<p style={{opacity: "70%"}}>You can add items in the form below. These tasks will automatically be added to your task list and your calendar.</p>
<hr className="mt-4 mb-2" />
<Col>
<Row className="mt-2">
<form className="p-2" onSubmit={submitHandler}>
<Row>
<OverlayTrigger
placement="top"
overlay={<Tooltip>Enter a title/name for your task.</Tooltip>}>
<Col md={8}>
<FormInput
name="title"
label="Title"
placeholder="Enter title"
type="text"
containerClass="mb-3"
className="form-control form-control-light"
key="title"
value={enteredTitle}
onChange={titleChangeHandler}
/>
</Col>
</OverlayTrigger>
<OverlayTrigger
placement="top"
overlay={<Tooltip>Set a priority status to your task.</Tooltip>}>
<Col md={4}>
<FormInput
name="priority"
label="Priority"
type="select"
containerClass="mb-3"
className="form-select form-control-light"
key="priority"
value={enteredPriority}
onChange={priorityChangeHandler}
>
<option>Select</option>
<option>Low</option>
<option>Medium</option>
<option>High</option>
</FormInput>
</Col>
</OverlayTrigger>
</Row>
<OverlayTrigger
placement="top"
overlay={<Tooltip>Enter a description to explain details about the task.</Tooltip>}>
<Col>
<FormInput
name="description"
label="Description"
type="textarea"
containerClass="mb-3"
className="form-control form-control-light"
rows="3"
key="description"
value={enteredDescription}
onChange={descriptionChangeHandler}
/>
</Col>
</OverlayTrigger>
<OverlayTrigger
placement="top"
overlay={<Tooltip>Enter the date when the task has to be finished.</Tooltip>}>
<div className="form-group">
<FormInput
name="dueDate"
label="Due Date"
type="date"
value={enteredDeadline}
onChange={deadlineChangeHandler}>
</FormInput>
</div>
</OverlayTrigger>
<br />
<Row>
<OverlayTrigger
placement="top"
overlay={<Tooltip>Set a start time for your task. The task will be listed in your personal calendar accordingly.</Tooltip>}>
<Col md={6}>
<div className="form-group">
<label className="form-label">Start time</label> <br />
<FormInput
type="datetime-local"
value={enteredStartTime}
onChange={startTimeChangeHandler}
/>
</div>
</Col>
</OverlayTrigger>
<OverlayTrigger
placement="top"
overlay={<Tooltip>Set an end time for your task. The task will be listed in your personal calendar accordingly.</Tooltip>}>
<Col md={6}>
<div className="form-group">
<label className="form-label">End time</label> <br />
<FormInput
type="datetime-local"
value={enteredEndTime}
onChange={endTimeChangeHandler}
/>
</div>
</Col>
</OverlayTrigger>
</Row>
<br />
<Row>
<OverlayTrigger
placement="top"
overlay={<Tooltip>Set the color with which you want your task to appear in the calendar.</Tooltip>}>
<Col md={6}>
<div className="form-group">
<label className="form-label">Color</label> <br />
<FormInput
type="color"
// value={enteredColor}
onChange={colorChangeHandler}
>
</FormInput>
{/* <CirclePicker /> */}
</div>
</Col>
</OverlayTrigger>
</Row>
<Col>
<button style={{marginTop: '50px', marginLeft: "23%", width: "300px"}} type="submit" className="btn btn-sm btn-success">
<i className="uil uil-message me-1"></i>Add Task
</button>
</Col>
</form>
</Row>
</Col>
</Card.Body>
</Card>
</React.Fragment>
);
};
export default Task;
Right now, I can submit and log the formdata to my console in the form of an object so I know the technique behind it works. However, I just can't seem to manage inserting it into my actual database.
If someone is able to help me out it would be wildly appreciated!
Kind regards,
Abbeneji
On the submitHandler, I can see that you have created a const taskData for managing your inputs, well!. you logged taskData on console seems fine on console as well, and again you set them empty and reusing that UseState const on request body, may they already set empty there. Also look at the payload data(Next after Headers tab) and compare it with the api request flow, which may helpful for you to debugging. There may be a chance of request payload formed incorrectly.

Not populating mongoDB database with data being entered on angular

I am writing a post form function using MEAN stack which saves the data to the DB.
When entering the data through postman on the node, express, mongoose side it stores in the database. however when entering the date through the angular frontend, the data isnt storing, this method i used for other forms and it worked however this one just doesn't:
HTML:
<form [formGroup]="form" (submit)="addMessage()">
<mat-form-field>
<mat-label>Username:</mat-label>
<input
placeholder="Username"
matInput
formControlName="username"
class="form-control"
type="string"
required
/>
</mat-form-field>
<br />
<mat-form-field>
<mat-label>Message:</mat-label>
<input
placeholder="Type Message Here..."
matInput
formControlName="message"
class="form-control"
type="string"
required
/>
</mat-form-field>
<br />
<mat-form-field>
<mat-label>Message Date:</mat-label>
<input
placeholder="Type Message Here..."
matInput
formControlName="messageDateTime"
class="form-control"
type="date"
required
/>
</mat-form-field>
<br />
<button mat-raised-button color="basic" type="submit">Send</button>
<br />
<mat-divider></mat-divider>
</form>
Typescript:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup } from '#angular/forms';
import { Router } from '#angular/router';
import { MessageBoardService } from 'src/app/service/message-board.service';
import { Message } from 'src/app/models/messages.interface';
#Component({
selector: 'app-message-board',
templateUrl: './message-board.component.html',
styleUrls: ['./message-board.component.css']
})
export class MessageBoardComponent implements OnInit {
messages: Message[] = [];
constructor(private messageService: MessageBoardService) { }
form = new FormGroup({
username: new FormControl(''),
message: new FormControl(''),
messageDateTime: new FormControl(''),
});
addMessage() {
console.log('adding');
const formData = new FormData();
formData.append('username', this.form.value.username);
formData.append('message',this.form.value.message);
formData.append('messageDateTime',this.form.value.messageDateTime);
this.messageService.postMessage(formData).subscribe((d) => {
console.log(d);
});
//window.location.reload();
}
ngOnInit(): void {
this.messageService.getMessage().subscribe((M: Message[]) => {
this.messages = M;
})
}
}
Service:
postMessage(data: any){
return this.http.post<any>("http://localhost:3000/Messages", data)
.pipe(map((res:any)=>{
return res;
}))
}
The get function works fine in the services it is only the post.
Posting data using postman works well, but from the frontend it just saves the default data that is set in the mongoose schema
Schema:
const mongoose = require('mongoose');
const MessagesSchema = new mongoose.Schema({
username:{
type: String,
required: false,
default: "User"
},
message:{
type: String,
required: false,
default:"Content"
},
messageDateTime:{
type: Date,
required: false,
default: Date.now
}
})
const Messages = mongoose.model( 'Messages', MessagesSchema);
module.exports = Messages
Data Entered Using Angular Frontend:
Data Saved in Database:
(Console Output):
{username: 'User', message: 'Content', messageDateTime:
'2022-03-04T23:23:32.040Z', _id: '62229f740a9c53a525774f01', __v: 0}
message: "Content" messageDateTime: "2022-03-04T23:23:32.040Z"
username: "User"
__v: 0
_id: "62229f740a9c53a525774f01" [[Prototype]]: Object
(Data stored accessed by postman):
{
"_id": "62229f740a9c53a525774f01",
"username": "User",
"message": "Content",
"messageDateTime": "2022-03-04T23:23:32.040Z",
"__v": 0
},
I'm not sure why do you need FormData, as I have never used it in Angular
I generally send data like this to backend
let dataToSend: any = {
username: this.form.value.username,
message: this.form.value.message,
messageDateTime: this.form.value.messageDateTime
}
this.messageService.postMessage(dataToSend).subscribe((d) => {
console.log(d);
});
I'll also update the service and Content-Type header, assuming your backend is expecting JSON.
let headers = new Headers();
headers.append('Content-Type', 'application/json');
postMessage(data: any)
{
http.post('http://localhost:3000/Messages', JSON.stringify(data), {
headers : headers
}).pipe('Rest of the Code');
}

Update data in mongodb with input valors

I have three input to obtain three different values. Im using express.js , node.js, mongodb and ejs templates.
<form action="/save-profile/<%= user.id %>/<%= user.name %>/<%= user.lastname %>/<%= user.description %>" method="POST">
<div class="input-group mb-3">
<span class="input-group-text" id="basic-addon1">Name</span><%= user.username %>
<input type="text" class="form-control" placeholder="'John'" aria-label="Username" name="username">
<span class="input-group-text">lastName</span><%= user.lastname %>
<input type="text" class="form-control" placeholder="" aria-label="Server" name="lastname">
</div>
<div class="input-group">
<span class="input-group-text">Description:</span>
<textarea class="form-control" aria-label="With textarea" placeholder="" name="description"><%= user.description %></textarea>
</div>
</p><br>
<button class="btn btn-primary mb-10 btn-lg">Save</button>
</div>
</div>
In js file:
router.post('/save-profile', async (req, res) => {
const profile_id = await User.findById({ _id: req.body.id })
const updatedName = await User.findOneAndUpdate({ username: req.body.username})
const updatedlastname = await User.findOneAndUpdate({ apellido: req.body.lastname })
const updatedDescription = await User.findOneAndUpdate({ description: req.body.description })
console.log(profile_id,updatedName,updatedApellido,updatedDescription)
res.redirect('/profile')})
I tried to do it with a get but it didn't work
Firstly, action attribute in the form tag accepts the path where you are handling the form data. You only need to pass the user.id, there's no need to pass the other fields for this use-case.
<form action="/save-profile/<%= user.id %>" method="POST">
...
</form>
Secondly, in your route handler, the database record can be updated using only a single findOneAndUpdate call. You don't need to call it multiple times for every field if you're only going to update a single record.
The path written in action attribute will appear as /save-profile/1, for instance, in your route handler. Value preceding /save-profile/ i.e. 1 can be accessed by modifying the path in route handler as /save-profile/:id and in the callback you can get it by req.params.id
Finally you have this.
router.post('/save-profile/:id', async (req, res) => {
const response = await User.findOneAndUpdate(
{ _id: req.params.id },
{
username: req.body.username,
apellido: req.body.lastname,
description: req.body.description
},
{ new: true }
)
// Do something with response
res.redirect('/profile')
})

Failing to make axios.put from react to node.js server

I have react component where i trying to change status of object. However I'm failing and didn't understand whether I'm on right way.
This is nodeJS server with express and mongoose.
Frond end side:
handleSubmit2(event){
const body= {status: this.state.newstatus}
event.preventDefault()
axios.put('http://127.0.0.1:3010/api/users/:user_id',{body})
alert("Status Changed")
}
in render:
{hits.map(item => <li key={item._id}> {item.firstname} {item.lastname} <br /> <strong> {item.status}</strong>
<form autoComplete="off" className="new_status" onSubmit={this.handleSubmit2}>
<FormControl>{this.loadoptions()}</FormControl>
<input type="submit" value="Submit" className="input"/>
<br />
</form>
My back-end:
router.put( '/:user_id', ( req, res ) => {
console.log(req.body.body.status)
User.findByIdAndUpdate(req.params.user_id, req.body.body.status)
.then(data => {
if(follower)
res.send(data);
else
res.status(404).send("Follower not found");
})
.catch (e => res.status(400).send("Follower not exist"));
});
UserSchema:
const userSchema = new mongoose.Schema ({
firstname: String,
lastname: String,
status: String
});
const User = mongoose.model('User', userSchema);
Link to git:
https://github.com/fmpro12/users_add
When i submit form i want to change status of specific people from array.
What I'm doing wrong?

How to combine schema model with file upload in Node.js and MongoDB?

Good day everyone, I am building a web application to store employee information in a local database. I have written the necessary code so that the client can input the required information such as Name, email, phone number etc. via a form and save it to MongoDB. Now I would like to add a file upload feature so that documents can be uploaded alongside employee information, such as insurance policies, passport copies etc. I am struggling to find a way to implement this as a lot methods online show implementations of CRUD and file uploads separately. Is there anyone experienced who would be able to suggest an implementation approach? I'm new to Node dev and not familiar with the vast selection of available frameworks. So far I have the following set up:
Frameworks used: Express, Mongoose, Express-Handlebars (view engine), Bootstrap
employee.Model:
const mongoose = require('mongoose');
const mongoURI = 'mongodb://localhost:27017/testDB'
const conn = mongoose.createConnection(mongoURI, {useNewUrlParser: true});
Schema = mongoose.Schema;
var employeeSchema = new Schema({
fullName: {
type: String,
required: true
},
email: {
type: String
},
mobile: {
type: String
},
city: {
type: String
}
});
const Employee = conn.model('Employee', employeeSchema);
module.exports = Employee;
Employee Controller:
const mongoose = require ('mongoose');
const express = require ('express');
var router = express.Router();
const Employee = require('../models/employee.model');
router.post('/', (req, res) => {
insertRecord(req, res);
});
function insertRecord (req, res) {
var employee = new Employee();
employee.fullName = req.body.fullName;
employee.email = req.body.email;
employee.mobile = req.body.mobile;
employee.city = req.body.city;
employee.save((err, doc) =>{
if (!err)
res.redirect('employee/list');
else {
console.log('Error during record insertion: ' + err);
}
});
}
Handlebars View:
<h3>{{viewTitle}}</h3>
<form action="/employee" method="POST" autocomplete="off">
<div class="form-group">
<label>Full Name</label>
<input type="text" class="form-control" name="fullName"
placeholder="Full Name">
</div>
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email"
placeholder="Email">
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>Mobile</label>
<input type="text" class="form-control" name="mobile"
placeholder="Mobile">
</div>
<div class="form-group col-md-6">
<label>City</label>
<input type="text" class="form-control" name="city"
placeholder="City">
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-info"><i class="fa fa-
database"></i> Submit</button>
</div>
</form>
Uploaded files are inputs just like others, they just need the specific enctype="multipart/form-data" attribute on the HTML side, and a proper handling on the server.
And easy-to-grasp demonstration using Multer (based on their own examples actually):
const upload = require('multer')({dest: 'uploads/'}); // npm i multer
const fileUploadMiddleware = upload.fields({
{name: 'resume', maxCount: 1},
{name: 'insurance', maxCount: 4}
});
router.post('/', fileUploadMiddleware, (req, res) => {
insertRecord(req, res);
});
function insertRecord(req, res) {
...
console.log(req.files.resume[0].mimetype); // this is resume file type
console.log(req.files.insurance[0].path); // this is first insurance file path
console.log(req.body.fullName); // this still works
}

Resources