I am trying to submit a form to create a new Appointment in my mongo database. When the form submits, I get a validation error telling me that certain fields are required. I have console.logged the fields from the form (as you can see under "Controllers") and they are empty. I have tried tracing the submission process, but I have no idea where the form is losing the information. I currently have the exact same setup for submitting a new car into my database and it works perfectly. The same console.logs in my car submission controller print out the new car object. I provided my routing, appointment model, controllers and form code below. I successfully reach the console.logs in my controller so I do not think it is a routing issue. I have also included the exact error message I get at the end of this post. I believe the form loses all data sometime between submission and validation, but I am not sure how to debug that, and am totally lost on how to fix this issue.
Routing:
const express = require('express');
const router = express.Router();
const appts = require('../controllers/appointments');
const catchAsync = require('../utils/catchAsync');
const { isLoggedIn, isAuthor } = require('../middleware');
const Appt = require('../models/appointments');
router.route('/')
.get(catchAsync(appts.index))
.post(catchAsync(appts.createAppt));
router.get('/new',appts.renderNewForm);
module.exports = router;
Controller:
const Appt = require('../models/appointments');
module.exports.createAppt = async (req,res) =>{
const appt = new Appt(req.body.appt);
console.log("Body: ",req.body);
console.log("Body: ",req.body.appt);
console.log("appt: ",appt);
//campground.author = req.user._id;
await appt.save();
req.flash('success', 'Successfully sent! Thank you for scheduling some time to meet with us, see you soon!');
res.redirect(`/cars`);
}
Model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ApptSchema = new Schema({
name:String,
email:{
type:String,
required: true
},
phone:{
type:Number,
required: true
},
date:{
type:Date,
required: true
},
time:{
type:String,
required: true
},
interests: String,
scheduleTime:Date
});
module.exports = mongoose.model('Appointment',ApptSchema);
Form:
<% layout('layouts/boilerplate')%>
<div class="display-3 text-center">SCHEDULE AN APPOINTMENT ONLINE:</div>
<div class="row">
<div class="col-md-6 offset-md-3">
<form action="/appointments" method="POST" novalidate class="validated-form" enctype="multipart/form-data">
<div class="mb-3">
<label class="form-label" for="name">Name</label>
<input class="form-control" type="text" id="name" name="appt[name]" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="mb-3">
<label class="form-label" for="email">Email</label>
<input class="form-control" type="email" id="email" name="appt[email]" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="mb-3">
<label class="form-label" for="phone">Phone Number:</label>
<input class="form-control" type="tel" id="phone" name="appt[phone]" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" required>
<small>Format: 555-456-7890</small>
</div>
<div class="mb-3">
<label for="date" class="form-label">Please Enter your Prefered Date</label>
<input class="form-control" type="date" id="date" name="appt[date]" required>
</div>
<div class="mb-3">
<label for="time" class="form-label">Please Select a Time Slot</label>
<select class="form-control" id="time" name="appt[time]" required>
<option value="morning">Morning (10-11:30am)</option>
<option value="afternoon">Afternoon (12-2:30pm)</option>
<option value="evening">Evening (3-4:30pm)</option>
</select>
</div>
<div class="mb-3">
<label class="form-label" for="interests">What are you interested in?</label>
<textarea class="form-control" type="text" id="interests" name="appt[interests]" placeholder="example: All wheel drive family car with great mileage." required></textarea>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="mb-3">
<label><strong>Appoitnment Request will be sent to Just Cars. You will shortly receive an email with a specified time within your time slot for your appointment.</strong></label>
</div>
<div class="mb-3 text-center">
<button class="btn btn-success">Request Appointment</button>
</div>
</form>
</div>
</div>
<div class="container">
<div class="row text-center" style="margin-top:40px; margin-bottom:50px;">
<div class="display-6"><strong>OTHER SCHEDULING OPTIONS, OR RESCHEDULE AN APPOINTMENT: </strong></div>
<div class="mt-4">
<a class = "btn btn-lg btn-outline-dark mx-3" href="tel:3853237118"><i class="fas fa-phone"></i> CALL US AT (385)323-7118</a>
<a class = "btn btn-lg btn-outline-dark mx-3" href="mailto:"><i class="fas fa-envelope"></i> SEND US AN EMAIL</a>
</div>
</div>
</div>
<hr class="my-4">
<div class="text-center"><a class="btn btn-dark" href="/cars">Back to All Cars</a></div>
Error from Browser
ValidationError: Appointment validation failed: time: Path `time` is required., date: Path `date` is required., phone: Path `phone` is required., email: Path `email` is required.
at model.Document.invalidate (/Users/Joselito/Desktop/JustCarsFinal/node_modules/mongoose/lib/document.js:2626:32)
at /Users/Joselito/Desktop/JustCarsFinal/node_modules/mongoose/lib/document.js:2446:17
at /Users/Joselito/Desktop/JustCarsFinal/node_modules/mongoose/lib/schematype.js:1225:9
at process._tickCallback (internal/process/next_tick.js:61:11)
Changed enctype from "multipart/form-data" to "application/x-www-form-urlencoded" in my edit form and now everything works.
If anyone is able to explain this to me, I would very much appreciate it. I know that forms of enctype="multipart/form-data" are used for forms that require file input, but I thought they also work on forms without files. Is file input a requirements for "multipart/form-data" enctypes?
Related
I am relatively new to coding and have been working on a restful routes exercise for an online course using a MEN stack. In the exercise, I am trying to use a default image when no data is entered into the /new route form. I have already indicated a default image in my mongoose schema, but it doesn't seem to be working when I leave the image field blank on my form. It creates a new post with a "unknown" src attribute. I have attached code for my schema, my /new ejs form, and new and create routes. Thanks for any help!
(MONGOOSE SCHEMA)
var catSchema = new mongoose.Schema({
name : String,
description: String,
ranking: Number,
image: {type: String, default: "https://i.cubeupload.com/SnsWs2.png"},
created: {type:Date, default: Date.now}
(NEW AND CREATE ROUTES)
app.post("/cats", function(req,res){
Cat.create(req.body.cat, function(err,newBlog){
if(err){
res.redirect("/cats/new")
}else{
res.redirect("/cats")
}
});
});
(NEW ROUTE)
<%- include("partials/header") %>
<div class="container">
<form action="/cats" method="POST">
<div class="form-group">
<label required for="cat[name]">Name</label>
<input type="text" name="cat[name]" class="form-control" id="name" aria-describedby="emailHelp" placeholder="Enter cat name">
</div>
<div class="form-group">
<label for="cat[description]">Description</label>
<input type="text" class="form-control" name="cat[description]" placeholder="description">
</div>
<div class="form-group">
<label for="cat[ranking]">Ranking</label>
<input type="number" class="form-control" name="cat[ranking]" placeholder="Password">
</div>
<div class="form-group">
<label for="cat[image]">Ranking</label>
<input type="text" class="form-control" name="cat[image]" placeholder="image URL">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
I'm learning through a tutorial to create a form that sends data to my local server and I'm getting a time out error. It's my first time working on post requests using a node.js express application and I'm stuck.
This is the handlebars code:
form method="POST" action="send">
<div class="form-row">
<div class="col-md-4 mb-3">
<label for="validationServer01">First name</label>
<input type="text" class="form-control is-valid" id="validationServer01" placeholder="First name" value="Mark" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="col-md-4 mb-3">
<label for="validationServer02">Last name</label>
<input type="text" class="form-control is-valid" id="validationServer02" placeholder="Last name" value="Otto" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="col-md-4 mb-3">
<label for="validationServerUsername">Username</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroupPrepend3">#</span>
</div>
<input type="text" class="form-control is-invalid" id="validationServerUsername" placeholder="Username" aria-describedby="inputGroupPrepend3" required>
<div class="invalid-feedback">
Please choose a username.
</div>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-6 mb-3">
<label for="validationServer03">City</label>
<input type="text" class="form-control is-invalid" id="validationServer03" placeholder="City" required>
<div class="invalid-feedback">
Please provide a valid city.
</div>
</div>
<div class="col-md-3 mb-3">
<label for="validationServer04">State</label>
<input type="text" class="form-control is-invalid" id="validationServer04" placeholder="State" required>
<div class="invalid-feedback">
Please provide a valid state.
</div>
</div>
<div class="col-md-3 mb-3">
<label for="validationServer05">Zip</label>
<input type="text" class="form-control is-invalid" id="validationServer05" placeholder="Zip" required>
<div class="invalid-feedback">
Please provide a valid zip.
</div>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input is-invalid" type="checkbox" value="" id="invalidCheck3" required>
<label class="form-check-label" for="invalidCheck3">
Agree to terms and conditions
</label>
<div class="invalid-feedback">
You must agree before submitting.
</div>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
This is the entry point code:
onst express = require ('express');
const bodyParser = require ('body-parser');
const exphbs = require ('express-handlebars');
const nodemailer = require ('nodemailer');
const path = require ('path');
const app = express ();
//View Engine Setup
app.engine ('handlebars', exphbs());
app.set ('view engine', 'handlebars');
//Static Folder
app.use('/public', express.static(path.join(__dirname, 'public')));
//Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//route
app.get ('/', (req,res) => {
res.render('contact', {layout:false})
});
//post route for submission
app.post('/send', (req, res) => {
console.log(req.body);
});
app.listen (3000,() => console.log ('Server started...'));
All I'm getting on my server is: {} when I try to submit.
Whenever you send a form value to the server, always add name attribute to your input fields. Otherwise you won't get the request parameters (req.body) in the server side.
name attribute serves as a JSON property in your case. If you don't provide name attribute, the JSON won't get updated with the field values.
Take some time to read this tutorial:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data
enter code hereI want to create populating dropdown list. like one dropdown will have Car types (Sport, Luxury, SUV, etc) stored in mongodb using mongoose and another dropdown will have car names like (Ferrari, Lamborghini, Rollce Royece) also stored in mongodb. If i select car type as "sport" in one dropdown, another dropdown should show only sport cars name fetch from mongoDB using mongoose.
Express Js
app.get('/car', (req, res) => {
res.render('car/');
});
index.handlebars
<div class="row mb-3">
<div class="col">
<input type="hidden" name="_method" value="PUT">
<div class="form-group dropdown">
<label for="Category" value=""> Select Category </label>
<select class="form-control" id="" name="Category">
{{#each category}}
<option>{{category}}</option>
{{/each}}
</select>
</div>
</div>
<div class="col">
<div class="form-group dropdown">
<label for="Car" value=""> Select Car</label>
<select class="form-control" id="" name="Car">
{{#each Car}}
<option>{{car}}</option>
{{/each}}
</select>
</div>
</div>
</div>
Category model.js
const CarSchema= new Schema({
Category: {
type: String,
required: true
},
CarName: {
type: String,
required: true
}
});
So I have a post method in my nodejs application and I want to send a form from my ejs file to an array in one of my models. In the ejs file, I have a select option for the user to enter a list of subjects. Once submitted, I cannot get the values from the select option. I tried to store it in an array but it shows undefined. I have an instructor model where it stores the subjects fields in a list of string array. I am not sure what to do. Here is what I have:
admin.js
router.get('/newInstructor', isLoggedIn, function(req, res) {
res.render('newInstructor.ejs');
});
router.post('/newInstructor', isLoggedIn, function(req, res) {
var lisOfSubjects = [req.body.listOfSubjects];
console.log('Subjects -> ' + lisOfSubjects);
var newInstructor = new Instructor ({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
officeNumber: req.body.officeNum,
cellNumber: req.body.cellNum,
address: {
address1: req.body.address,
address2: req.body.address2,
city: req.body.city,
state: req.body.state,
zipCode: req.body.zip
},
subjects: lisOfSubjects,
officeLocation: req.body.officeLocation
});
console.log(newInstructor);
});
ejs view file
<!-- js function to insert and remove from the select option-->
<script>
function insertTeachingSelect() {
var text = document.getElementById("subject").value;
console.log(text);
var select = document.getElementById("listOfSubjects");
select.options[select.options.length] = new Option(text, 'Value1');
}
function removeTeachingSelect() {
var removeSelect = document.getElementById("listOfSubjects");
removeSelect.remove(removeSelect.selectedIndex);
}
</script>
......
<div class="form-group">
<div class="form-row">
<div class="col-md-4">
<div class="form-label-group">
<input type="text" id="subject" name="subject" class="form-control">
<label for="Enter subject">Enter subject</label>
</div>
</div>
<div class="col-md-2">
<div class="form-label-group">
<input type="button" onclick="insertTeachingSelect()" class="btn btn-primary btn-block" value="Add more">
<input type="button" onclick="removeTeachingSelect()" class="btn btn-primary btn-block" value="Remove">
</div>
</div>
<div class="col-md-6">
<div class="form-label-group">
<input type="text" id="officeLocation" name="officeLocation" class="form-control" placeholder="Office location" required="required">
<label for="officeLocation">Office location</label>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-md-4">
<div class="form-label-group">
<select id="listOfSubjects" name="listOfSubjects"size="5"></select>
</div>
</div>
</div>
</div>
<div class="form-group ">
<div class="form-row">
<div class="col-md-6 mx-auto">
<div class="form-label-group">
<button type="submit" class="btn btn-primary btn-block">Submit</button>
I'm trying to parse a model from a form which contain a select(ngOptions) and save it to db but the selected value is never parsed. i'm stuck here can someone help please.
here is my code:
View
<section class="container" data-ng-controller="TagsController" >
<h2><i class="fa fa-pencil-square-o"></i>Add a new Tag</h2>
<form class="form-horizontal col-md-5" data-ng-submit="create()">
<div class="form-group ">
<div class="controls">
<input type="text" class="form-control input-lg" data-ng-model="label" id="label" placeholder="Label" required>
</div>
</div>
<div class="form-group" data-ng-controller="CategoriesController" data-ng-init="find()">
<select class="form-control input-lg" ng-model="category._id" ng-options="category._id as category.label for category in categories">
<option value="">Choose a Category</option>
</select>
</div>
<div class="control-group">
<div class="controls">
<input type="submit" class="btn">
</div>
</div>
</form>
</section>
controller
angular.module('mean.tags').controller('TagsController', ['$scope', '$routeParams', '$location', 'Global', 'Tags', function ($scope, $routeParams, $location, Global, Tags) {
$scope.global = Global;
$scope.create = function() {
var tag = new Tags({
label: this.label,
category: this.category
});
tag.$save(function(response) {
$location.path("tags/");
});
this.label = "";
this.category = "";
};
...
I found the problem so i will answer my question. The problem was due to architecture restrictions, Angularjs don't allow to nest a ng-controller inside an other one...