Mongoose not updating database with findByIdAndUpdate? - javascript

I am trying to update my database using findByIdAndUpdate through an HTML form, which works for all but the nested data (ePIMS, codeVersion, and region all update with no problem). When I do console.log(req.body.environment.instance), it outputs the data I typed in like it's going through correctly, but for some reason the mongoDB does not update with the information. Can anyone figure out what I'm doing wrong?
mongoose schema:
var environmentSchema = new mongoose.Schema({
ePIMS: String,
codeVersion: String,
region: String,
/*instance and testEnv don't seem to update in the database*/
HCHC: {
instance: String,
testEnv: String
}
});
form I'm using to update:
<form action="/environments/<%= environment._id %>?_method=PUT" method="POST">
<input class="form-control" type="text" name="environment[ePIMS]" placeholder="ePIMS" value="<%= environment.ePIMS %>" />
<input class="form-control" type="text" name="environment[region]" placeholder="Region" value="<%= environment.region %>" />
<input class="form-control" type="text" name="environment[instance]" placeholder="HCHC Instance" value="<%= environment.instance %>" />
<input class="form-control" type="text" name="environment[testEnv]" placeholder="Test Environment" value="<%= environment.testEnv %>" />
<button class="btn btn-primary">Submit</button>
</form>
edit and update routes:
//Edit environment route
router.get("/environments/:id/edit", function(req, res){
Environment.findById(req.params.id, function(err, foundEnvironment){
if(err){
res.redirect("/");
} else {
res.render("edit", {environment: foundEnvironment});
}
});
});
//Update environment route
router.put("/environments/:id", function(req, res){
Environment.findByIdAndUpdate(req.params.id, req.body.environment, function(err, updatedEnvironment){
if (err) {
res.redirect("/environments");
} else {
res.redirect("/environments");
//console.log(req.body.environment.instance)
}
});
});
UPDATE: SOLUTION
Thank you Nayan for your help!
I changed the update route like so:
//Update environment route
router.put("/environments/:id", function(req, res){
var data = {
HCHC : {
instance: req.body.instance,
testEnv: req.body.testEnv
}
}
Environment.findByIdAndUpdate(req.params.id, {$set: data}, function(err, updatedEnvironment){
if (err) {
res.redirect("/environments");
} else {
res.redirect("/environments");
}
});
});

You are sending different body structures and setting it directly in findOneAndUpdate() so it didn't work, where the structure is different.
The possible solution you can apply is to change the body of the request to look something like this:
"environment" : {
"ePIMS" : value,
"codeVersion" : value,
"region" : value,
"HCHC": {
"instance" : value,
"testEnv" : value
}
}
Or you can put the two thing instance and testEnv out of HCHC if you want.
Either way make sure you have same structure if you are passing the body directly in the function.
Another solution
create a local variable to fix the structure and pass that in function like:
router.put("/environments/:id", function(req, res){
let body = req.body.environment
let bodyData = {
ePIMS: body.ePIMS,
codeVersion: body.codeVersion,
region: body.region,
HCHC: {
instance: body.instance,
testEnv: body.testEnv
}
}
Environment.findByIdAndUpdate(req.params.id, bodyData, function(err, updatedEnvironment){
if (err) {
res.redirect("/environments");
} else {
res.redirect("/environments");
//console.log(req.body.environment.instance)
}
});
});

this solution worked for me:
router.patch('/tasks/:id', async (req,res)=>{
try{
const task= await Task.findByIdAndUpdate(req.params.id,req.body,{new:true,runValidators:true})
if(!task)
{
res.status(404).send()
}
res.send(task)
}
catch(e)
{
res.status(500).send()
}
})
however,my final solution included validation was inplementing update without using findByIdAndUpdate:
router.patch('/tasks/:id', async (req,res)=>{
//validate update operation
const updates=Object.keys(req.body)
const allowedUpdates= ['description','completed']
const isInvalidOperation= updates.every((update)=>allowedUpdates.includes(update))
if(!isInvalidOperation)
{
return res.status(400).send({error:'invalid updates'})
}
try{
const task= await Task.findById(req.params.id)
updates.forEach((update)=>task[update]=req.body[update])
await task.save()
if(!task)
{
res.status(404).send()
}
res.send(task)
}
catch(e)
{
res.status(500).send()
}
})

Related

Add Update Functionality

Sorry if this is super obvious, but I'm new to coding. I'm using node.js, express, mongoose and mongodb to try and add an update function to my app to make it CRUD by adding an edit button. Whenever I click the edit button though it still just deletes the item as if I were clicking the checkbox. I'm thinking it's because I'm calling the item from the same form of "pending items" but it seems like my update code isn't even registering as my console.logs for //Edit items aren't logging.
I want it to identify the item by its id when its edit button is submitted (then put the item in the newTask input to be edited and resubmitted as an update but I haven't figured out how to link those 2). I know the code is wonky, I'm just trying to figure out how to put this together, so thanks for any help!
<div class="box">
<!-- Item add function -->
<% newListItems.forEach(function(item){ %>
<!-- Form for pending items -->
<form action="/update" method="post">
<!-- Items -->
<div class="item">
<input type="checkbox" name="checkbox" value="<%=item._id%>" onChange="this.form.submit()">
<button type="submit" class="editItmbtn" name="editItembtn">E</button>
<p><%=item.name%></p>
</div>
<input type="hidden" name="listName" value="<%= listTitle %>"></input>
</form>
<% }) %>
<!-- End pending items -->
<!-- Form to add items -->
<form class="item" action="/" method="post">
<input type="text" name="newTask" id="id" placeholder="Add new task..." autocomplete="off">
<button type="submit" name="list" value="<%= listTitle %>">+</button>
</form>
</div>
''//Requirements
const express = require("express");
const session = require("express-session")//for sessions
const favicon = require("serve-favicon"); //for favicon
const path = require("path");// for favicon
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser"); //for sessions
const mongoose = require("mongoose"); const _ = require("lodash");
const MongoStore = require("connect-mongo")(session);
const app = express();
// Edit items
app.put("/update", function(req, res) {
const itemName = req.body.newTask;
const taskID = req.body.editItmbtn;
const userInput = req.body.id;
Item.useFindAndModify(taskID), {
$set: {"/update": userInput}}, {new: true},
(err, result) => {
if (err) {
console.log("ERROR");
} else {
res.redirect("/");
res.render("list", {
listTitle: "Tasks",
newListItems: foundItems
});
}
}
});
// Delete checked items
app.post("/update", function(req, res) {
const checkedItemId = req.body.checkbox;
const listName = req.body.listName;
if (listName === "Tasks") {
Item.findByIdAndRemove(checkedItemId, function(err) {
if (!err) {
console.log("Successfully deleted checked item.");
res.redirect("/");
}
});
} else {
List.findOneAndUpdate({
name: listName
}, {
$pull: {
items: {
_id: checkedItemId
}
}
}, function(err, foundList) {
if (!err) {
res.redirect("/" + listName);
}
});
}
});
In your form you are using the method="post" which means that the request will be submitted to your app.post("/update" ..... ) , that is why you always land there, where you delete your item.
You have to do two things:
Change the app.put('/update' ...) to app.post('/update' ...)
Change the app.post('/update' ... which is meant to delete the item to something semantically more relevant like maybe app.post('/delete' ... and change the frontend with which you delete method respectively.
You have app.put("/update", function(req, res) in Express but <form action="/update" method="post"> in your form, which matches your delete route.
For your second question, there are many ways to populate your item form in Javascript, but there might be an even more efficient way if you tell us if you're using a framework.
Your form always submit the http request with the "POST" method, but in your code the app.post("update") deletes the item

Cast to ObjectId failed for value \":5e1360c5edb2922570aa2611\" at path \"_id\" for model \"colt\"" error

I am creating a program to perform CRUD operations and I am getting an error:
Cast to ObjectId failed for value \":5e1360c5edb2922570aa2611\" at
path \"_id\" for model \"colt\"",
Here is my code:
// here is the route of edit path
app.get("/edit/:ids", (req, res) => {
colt.findById(req.params.ids, (err, coltz) => {
if (err) {
res.redirect("/");
} else {
res.render("showedit", { colt: coltz });
}
});
});
// here is the update route
app.put("/edit/:ids", (req, res) => {
colt.findByIdAndUpdate(req.params.ids, req.body.colts, err => {
if (err) {
res.send(err);
} else {
res.redirect("/show");
}
});
});
Here is the show edit ejs file:
<h1>HELLO HERE YOU CAN UPDATE</h1>
<form action="/edit/:<%=colt._id%>?_method=PUT" method="POST">
<input type="text" placeholder="name here" name="colts[name]" value="<%= colt.name %>">
<input type="text" placeholder="description here" name="colts[description]" value="<%= colt.description %>">
<input type="text" placeholder="img url here" name="colts[url]" value="<%= colt.url %>">
<input type="submit">
</form>
And this is my mongoose schema:
var coltSchema = new mongoose.Schema({
name: String,
description: String,
url: String
});
let colt = mongoose.model("colt", coltSchema);
You don't have to write : in your link when using url params
<form action="/edit/:<%=colt._id%>?_method=PUT" method="POST"> // remove : from this line
Due to this, the value your route gets in ids is :5e1360c5edb2922570aa2611 instead of 5e1360c5edb2922570aa2611 only
Remove the : from url of form action & you're good to go

Passing MongoDB Data into .ejs-Template with Node.js Express

I think i clicked myself through thousands of tutorials but i'm still stucked at this point: I want to render all the data, which my express-app is writing into mongodb at its start, into embedded javascript. I would like to have a simple table which is showing all the data from mongodb. It shall also always get the actualized Data when calling the route.
My first idea was, to save the data in an array. Pass it to the .ejs file. Create a table, iterate through my data-array and write it in. My problem is, that i can not write the data into an array after calling the find()-Function.
The model subscriber.js:
const mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
var subscriberSchema = mongoose.Schema({
nr: Number,
mailIdent: {
type: String,
unique: true
},
from: String,
emails: {
type: String,
default: ''
},
text: String,
uLink: String,
anwalt: Boolean,
create_date:{
type: Date,
default: Date.now
}
});
subscriberSchema.plugin(uniqueValidator);
var Subscriber = module.exports = mongoose.model('Subscriber', subscriberSchema);
I'm really new to the topic and it feels like i'm just messing around. Please help
//get Subscriber
/*module.exports.getSubscribers = Subscriber.find(function(err, subs){
if(err) return console.error(err);
console.log(subs);
});
*/
module.exports.subscriber = Subscriber;
module.exports.getSubscriberByID = function(_id, callback){
Subscriber.findById(_id, callback);
};
module.exports.getSubscribers = function(){
var subscribers = Subscriber.find({});
return subscribers;
};
Then i want to pass it with my app.js to the index.ejs:
app.get('/', function(req, res){
var subs = Subscriber.getSubscribers().toArray();
console.log(subs);
res.render('index',{subs: subs} );
});
I know, that my .ejs still seems a little simple. But so far it shall be just functional:
<!DOCTYPE html>
<html>
<head>
<link href="/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<% include partials/nav.ejs %>
<h1>Welcome to the Database</h1>
<p>You won't find more Information than here!</p>
<p>Table</p>
<table>
<colgroup span="5" class="columns"></colgroup>
<tr>
<th>Nr</th>
<th>Name</th>
<th>Mail</th>
<th>uLink</th>
<th>Anwalt</th>
</tr>
<% for (var i = 0; i<subs.length; i++) { %>
<tr>
<td><%= subs[i].nr</td>
<td><%= subs[i].name</td>
<td><%= subs[i].email</td>
<td><%= subs[i].uLink</td>
<td><%= subs[i].anwalt</td>
</tr>
<% } %>
</table>
</body>
</html>
The following is from mongoose docs:
Query#find([criteria], [callback])
When no callback is passed, the
query is not executed. When the query is executed, the result will be
an array of documents.
You can use a callback just Like you do with getSubscriberByID function, here is an example:
subscriber.js:
...
module.exports.getSubscribers = function(cb){
Subscriber.find({}, cb);
};
app.js
app.get('/', function(req, res){
Subscriber.getSubscribers( function (err, subs) {
if (err) throw err;
// else render result
res.render('index', { subs: subs} );
});
});
here is ur app.js code..
app.get('/', (req, res) => {
// db.collection('story').aggregate([
// { $lookup:
// {
// from: 'story_content',
// localField: 'ObjectId("5a322e1130cb6225a086f37d")',
// foreignField: "5a322e1130cb6225a086f37d",
// as: 'joinstorydata'
// }
// }
// ]).toArray(function(err, res) {
// if (err) throw err;
// console.log("********************************************************")
// console.log(res);
// final=res;
// });
db.collection('bid_placement').find().toArray((err, docs2) => {
if (err) return console.log(err)
// renders index.ejs
lnames2 = [...new Set(docs2.map(a => a.bid_location))]
lnames2.sort();
res.render('index.ejs', {
//story12 : docs1 ,
//story_content: final,
storylocation : lnames2
});
});
});
and here is ur html code
<select name="Courses" id="Courses">
<% for(var i=0; i<storylocation.length; i++) {%>
<option value="<%= storylocation[i]%>"> <%= storylocation[i]%> </option>
<% } %>
</select>
you can use it like <%= storylocation[i].abc%> .. put you desire data instead of abc on each column of table...
It was driving me mad and finally i found out. I did not closed the Javascript in the .ejs file. That was definetly the most stupid misstake ever

Express Routes not functioning on Single Page Web App

I'm converting an old LAMP stack project to use Node/Express/MongoDB instead of PHP/Laravel/MySQL. I built out my routes the same way I did in Laravel and have tested the routes I've built using Postman. Every route works as it should through testing in Postman.
However, when I try to use these routes in the display.js file that I wrote, the only route that works is GET /players. I am looking for some insight on these routes and the display file I'm using.
When I click the edit button, my GET /player/:id route grabs the correct information (status code 200 and preview shows JSON object) but will not populate the fields in my form.
When I click the delete button, I get a 404 status code with a response of "Cannot GET /players/123/delete". How do I adjust my display code to use DELETE instead of GET? (I believe I can refactor my all of my routes to just /players/:id using the correct http request method if I can figure out how to pass the request method in the display.js code).
When I try to submit a new record, I get a 400 status code with validation error saying Path age is required. It's actually the same error for each field name, so I assume that I'm not passing the values from the field into the JSON object correctly.
I haven't been able to test patch, but believe it should be remedied through fixing DELETE /players/:id and GET /players/:id.
Any help is appreciated. Code is below for display and server js files.
display.js
// this is the base url to which all your requests will be made
var baseURL = window.location.origin;
$(document).ready(function(){
// $.ajaxSetup({
// headers: {
// 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
// }
// });
$('#table').click(function(event) { // generates the table
// change the url parameters based on your API here
// Using an JQuery AJAX GET request to get data form the server
$.getJSON(baseURL+'/players', function(data) {
generateTable(data, $('#container'));
});
});
$('#form').click(function(event) {
// creating an empty form
generateForm(null, $('#container'));
});
// Handle table click event for delete
$('#container').on('click', '.delete', function(event) {
var id = $(this).val();
// change the url parameters based on your API here
// remember to create delete functionality on the server side (Model and Controller)
// Using an JQuery AJAX GET request to get data form the server
$.getJSON(baseURL+"/players/"+id+"/delete", function(data) {
//Generate table again after delete
//change the url based on your API parameters here
// Using an JQuery AJAX GET request to get data from the server
$.getJSON(baseURL+'/players', function(data) {
generateTable(data, $('#container'));
});
});
});
// Handle form submit event for both update & create
// if the ID_FIELD is present the server would update the database otherwise the server would create a record in the database
$('#container').on('submit', '#my-form', function(event) {
var id = $('#id').val();
console.log(id);
if (id != "") {
event.preventDefault();
submitForm(baseURL+"/players/"+id+"/edit", $(this));
} else {
event.preventDefault();
submitForm(baseURL+"/player", $(this));
}
});
// Handle table click event for edit
// generates form with prefilled values
$('#container').on('click', '.edit', function(event) {
// getting id to make the AJAX request
var id = $(this).val();
// change the url parameters based on your API here
// Using an JQuery AJAX GET request to get data form the server
$.getJSON(baseURL+'/players/'+id, function(data) {
generateForm(data, $('#container'));
});
});
// function to generate table
function generateTable(data, target) {
clearContainer(target);
//Change the table according to your data
var tableHtml = '<table><thead><tr><th>Name</th><th>Age</th><th>Position</th><th>Team</th><th>Delete</th><th>Edit</th></tr></thead>';
$.each(data, function(index, val) {
tableHtml += '<tr><td>'+val.playername+'</td><td>'+val.age+'</td><td>'+val.position+'</td><td>'+val.team+'</td><td><button class="delete" value="'+val._id+'">Delete</button></td><td><button class="edit" value="'+val._id+'">Edit</button></td></tr>';
});
tableHtml += '</table>';
$(target).append(tableHtml);
}
// function to generate form
function generateForm(data, target){
clearContainer(target);
//Change form according to your fields
$(target).append('<form id="my-form"></form>');
var innerForm = '<fieldset><legend>Player Form</legend><p><label>Player Name: </label>'+'<input type="hidden" name="id" id="id"/>'+'<input type="text" name="playername" id="playername" /></p>' + '<p><label>Age: </label><input type="text" name="age" id="age" /></p>'+ '<p><label>Hometown: </label><input type="text" name="city" id="city" />'+ ' ' + '<input type="text" name="country" id="country" /></p>' + '<p><label>Gender: </label><input type="text" name="gender" id="gender" /></p>'+ '<p><label>Handedness: </label><input type="text" name="handedness" id="handedness" /></p>'+ '<p><label>Broom: </label><input type="text" name="broom" id="broom" /></p>'+ '<p><label>Position: </label><input type="text" name="position" id="position" /></p>'+ '<p><label>Team: </label><input type="text" name="team" id="team" /></p>'+ '<p><label>Favorite Color: </label><input type="text" name="favoritecolor" id="favoritecolor" /></p>'+ '<p><label>Headshot: </label><input type="text" name="headshot" id="Headshot" /></p>'+ '<input type="submit"/>';
$('#my-form').append(innerForm);
//Change values according to your data
if(data != null){
$.each(data, function(index, val) {
$('#id').val(val._id);
$('#playername').val(val.playername);
$('#age').val(val.age);
$('#city').val(val.city);
$('#country').val(val.country);
$('#gender').val(val.gender);
$('#handedness').val(val.handedness);
$('#broom').val(val.broom);
$('#position').val(val.position);
$('#team').val(val.team);
$('#favoritecolor').val(val.favoritecolor);
$('#Headshot').val(val.headshot);
});
}
}
function submitForm(url, form){
$.post(url, form.serialize(), function(data) {
showNotification(data, $('#notification'));
});
}
function showNotification(data, target){
clearContainer(target);
target.append('<p>'+data+'</p>');
}
function clearContainer(container){
container.html('');
}
});
server.js
const _ = require('lodash');
const {ObjectID} = require('mongodb');
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
var {mongoose} = require('./db/mongoose');
var {Player} = require('./models/player');
var app = express();
const port = process.env.PORT || 3000;
app.use(express.static(__dirname+'./../public'));
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.sendFile('index.html');
});
app.post('/player', (req, res) => {
var player = new Player({
playername: req.body.playername,
age: req.body.age,
city: req.body.city,
country: req.body.country,
gender: req.body.gender,
handedness: req.body.handedness,
broom: req.body.broom,
position: req.body.position,
team: req.body.team,
favoritecolor: req.body.favoritecolor,
headshot: req.body.headshot
});
player.save().then((doc) => {
res.send(doc);
}, (e) => {
res.status(400).send(e);
});
});
app.get('/players', (req, res) => {
Player.find().then((players) => {
res.send(players);
}, (e) => {
res.status(400).send(e);
});
});
app.get('/players/:id', (req, res) => {
var id = req.params.id;
if (!ObjectID.isValid(id)) {
return res.status(404).send();
}
Player.findById(id).then((player) => {
if (player) {
res.send(player);
} else {
return res.status(404).send();
}
}).catch((e) => {
res.status(400).send();
});
});
app.delete('/players/:id/delete', (req, res) => {
var id = req.params.id;
if (!ObjectID.isValid(id)) {
return res.status(404).send();
}
Player.findByIdAndRemove(id).then((player) => {
if (player) {
res.send(player);
} else {
return res.status(404).send();
}
}).catch((e) => {
res.status(400).send();
});
});
app.patch('/players/:id/edit', (req, res) => {
var id = req.params.id;
var body = _.pick(req.body, ['playername', 'age', 'city', 'country', 'gender', 'handedness', 'broom', 'position', 'team', 'favoritecolor', 'headshot']);
if (!ObjectID.isValid(id)) {
return res.status(404).send();
}
Player.findByIdAndUpdate(id, {$set: body}, {new: true}).then((player) => {
if (!player) {
return res.status(404).send();
} else {
res.send(player);
}
}).catch((e) => {
res.status(400).send();
})
});
app.listen(port, () => {
console.log(`Started on port ${port}`);
});
module.exports = {app};
When I click the delete button, I get a 404 status code with a response of "Cannot GET /players/123/delete". How do I adjust my display code to use DELETE instead of GET? (I believe I can refactor my all of my routes to just /players/:id using the correct http request method if I can figure out how to pass the request method in the display.js code).
This is because your app has app.delete('/players/:id/delete') and not app.get('/players/:id/delete'). However, your server side code shouldn't change much, just one tweak:
If you have an app.delete() then really no need to have the verb delete at the end of the resource.
Also you need to make the request using the HTTP Method DELETE instead of making a GET in display.js. Just make the DELETE request using $.ajax() with type set to 'DELETE'
When I click the edit button, my GET /player/:id route grabs the correct information (status code 200 and preview shows JSON object) but will not populate the fields in my form.
This is because your implementation of $.each() assumes data will always be an Array and not ever and object, however, your generateForm() is passing in a Player object. Change your $.each() to do type checking for array handling and object handling. See below changes.
When I try to submit a new record, I get a 400 status code with validation error saying Path age is required. It's actually the same error for each field name, so I assume that I'm not passing the values from the field into the JSON object correctly.
If you make the above change to generateForm() it should fix this.
Just take the below snippets and replace those sections within your app, it should work.
server.js
app.delete('/players/:id', (req, res) => {
var id = req.params.id;
if (!ObjectID.isValid(id)) {
return res.status(404).send();
}
return Player.findByIdAndRemove(id).then((player) => {
if (player) {
res.status(200).json(player);
} else {
return res.status(404).send();
}
}).catch((e) => {
res.status(400).send();
});
});
app.patch('/players/:id', (req, res) => {
var id = req.params.id;
var body = _.pick(req.body, ['playername', 'age', 'city', 'country', 'gender', 'handedness', 'broom', 'position', 'team', 'favoritecolor', 'headshot']);
if (!ObjectID.isValid(id)) {
return res.status(404).send();
}
Player.findByIdAndUpdate(id, {$set: body}, {new: true}).then((player) => {
if (!player) {
return res.status(404).send();
} else {
res.status(200).json(player);
}
}).catch((e) => {
res.status(400).send();
})
});
app.post('/players', (req, res) => {
var player = new Player({
playername: req.body.playername,
age: req.body.age,
city: req.body.city,
country: req.body.country,
gender: req.body.gender,
handedness: req.body.handedness,
broom: req.body.broom,
position: req.body.position,
team: req.body.team,
favoritecolor: req.body.favoritecolor,
headshot: req.body.headshot
});
return player.save().then((doc) => {
return res.status(200).json(doc);
}, (e) => {a
return res.status(400).send(e);
});
});
display.js
// Handle form submit event for both update & create
// if the ID_FIELD is present the server would update the database otherwise the server would create a record in the database
$('#container').on('submit', '#my-form', function(event) {
var id = $('#id').val();
let formData = {};
$.each($('#myForm').serializeArray(), function(_, kv) {
if (formData.hasOwnProperty(kv.name)) {
formData[kv.name] = $.makeArray(formData[kv.name]);
formData[kv.name].push(kv.value);
}
else {
formData[kv.name] = kv.value;
}
});
console.log(id);
if (id != "") {
event.preventDefault();
$.ajax({
url: baseURL + '/players/' + id,
type: 'PATCH',
success: function(edited) {
// Handle returned edited player
}
})
} else {
event.preventDefault();
$.ajax({
url: baseURL + '/players',
type: 'POST',
success: function(created) {
// Handle created player
}
})
}
});
// Handle table click event for delete
$('#container').on('click', '.delete', function(event) {
var id = $(this).val();
// change the url parameters based on your API here
// remember to create delete functionality on the server side (Model and Controller)
// Using an JQuery AJAX GET request to get data form the server
$.ajax({
url: baseURL + '/players/' + id,
type: 'DELETE',
success: function(data) {
//Generate table again after delete
//change the url based on your API parameters here
// Using an JQuery AJAX GET request to get data from the server
$.getJSON(baseURL+'/players', function(data) {
generateTable(data, $('#container'));
});
}
});
});
// function to generate form
function generateForm(data, target){
clearContainer(target);
//Change form according to your fields
$(target).append('<form id="my-form"></form>');
var innerForm = '<fieldset><legend>Player Form</legend><p><label>Player Name: </label>'+'<input type="hidden" name="id" id="id"/>'+'<input type="text" name="playername" id="playername" /></p>' + '<p><label>Age: </label><input type="text" name="age" id="age" /></p>'+ '<p><label>Hometown: </label><input type="text" name="city" id="city" />'+ ' ' + '<input type="text" name="country" id="country" /></p>' + '<p><label>Gender: </label><input type="text" name="gender" id="gender" /></p>'+ '<p><label>Handedness: </label><input type="text" name="handedness" id="handedness" /></p>'+ '<p><label>Broom: </label><input type="text" name="broom" id="broom" /></p>'+ '<p><label>Position: </label><input type="text" name="position" id="position" /></p>'+ '<p><label>Team: </label><input type="text" name="team" id="team" /></p>'+ '<p><label>Favorite Color: </label><input type="text" name="favoritecolor" id="favoritecolor" /></p>'+ '<p><label>Headshot: </label><input type="text" name="headshot" id="Headshot" /></p>'+ '<input type="submit"/>';
$('#my-form').append(innerForm);
//Change values according to your data
if(data instanceof Array){
$.each(data, function(index, val) {
$('#id').val(val._id);
$('#playername').val(val.playername);
$('#age').val(val.age);
$('#city').val(val.city);
$('#country').val(val.country);
$('#gender').val(val.gender);
$('#handedness').val(val.handedness);
$('#broom').val(val.broom);
$('#position').val(val.position);
$('#team').val(val.team);
$('#favoritecolor').val(val.favoritecolor);
$('#Headshot').val(val.headshot);
});
}
else if (typeof data === 'object') {
$.each(data, function(key, value) => {
$('#' + key).val(value);
});
}
}
Try res.json(player); instead of res.send(player); in order to send the data in JSON format.
Also, instead of $.post(url, form.serialize(), function(data) {try the code from this answer in order to send the data in JSON format.

SequelizeJS Passing Array of Values

I am trying to figure out how it is possible to pass an array as the value for the property of an instance. I currently have the dataType set to STRING in my model and have values from jQuery fields insert each form field value into an array that I parse from the body and set to the property, discoverSource. Unfortunately I receive a string violation error that says I can't use an array or object. What does this mean and how can I change the dataType of the field or route to allow me to pass the comma separated values to the field?
E.x. For discoverySource I pass values to two fields (NJ, NY). On submit, the values are combined in an array as ["NJ", "NY"] and the error displays:
Error Message:
{"name":"SequelizeValidationError","message":"string violation: discoverySource cannot be an array or an object","errors":[{"message":"discoverySource cannot be an array or an object","type":"string violation","path":"discoverySource","value":["NJ","NY"]}]}
Here is my model:
module.exports = function(sequelize, DataTypes) {
var Organization = sequelize.define('organization', {
organizationId: {
type: DataTypes.INTEGER,
field: 'organization_id',
autoIncrement: true,
primaryKey: true
},
organizationName: {
type: DataTypes.STRING,
field: 'organization_name'
},
admin: DataTypes.STRING,
discoverySource: {
type: DataTypes.TEXT,
field: 'discovery_source'
},
members: DataTypes.STRING
},{
freezeTableName: true,
classMethods: {
associate: function(db) {
Organization.belongsToMany(db.User, { through: 'member', foreignKey: 'user_id' });
},
},
});
return Organization;
}
Here is the route:
var express = require('express');
var appRoutes = express.Router();
var passport = require('passport');
var localStrategy = require('passport-local').Strategy;
var models = require('../models/db-index');
appRoutes.route('/sign-up/organization')
.get(function(req, res){
models.User.find({
where: {
user_id: req.user.email
}, attributes: [ 'user_id', 'email'
]
}).then(function(user){
res.render('pages/app/sign-up-organization.hbs',{
user: req.user
});
})
})
.post(function(req, res, user){
models.Organization.create({
organizationName: req.body.organizationName,
admin: req.body.admin,
discoverySource: req.body.discoverySource
}).then(function(organization, user){
res.redirect('/app');
}).catch(function(error){
res.send(error);
console.log('Error at Post' + error);
})
});
Here is my view file:
<!DOCTYPE html>
<head>
{{> head}}
</head>
<body>
{{> navigation}}
<div class="container">
<div class="col-md-6 col-md-offset-3">
<form action="/app/sign-up/organization" method="post">
<p>{{user.email}}</p>
<input type="hidden" name="admin" value="{{user.email}}">
<input type="hidden" name="organizationId">
<label for="sign-up-organization">Company/Organization Name</label>
<input type="text" class="form-control" id="sign-up-organization" name="organizationName" value="" placeholder="Company/Organization">
Add Another Discovery Source
<div id="sign-up-organization-discovery-source">
<input type="text" id="discovery-source-field" placeholder="Discovery Source" name="discoverySource[0]">
</div>
<br />
<button type="submit">Submit</button>
</form>
Already have an account? Login here!
</div>
</div>
<script type="text/javascript">
$(function() {
var dataSourceField = $('#sign-up-organization-discovery-source');
var i = $('#sign-up-organization-discovery-source p').size();
var sourceCounter = 1;
$('#sign-up-add-discovery-source').on('click', function() {
$('<p><label for="discovery-source-field"><input type="text" id="discovery-source-field" size="20" name="discoverySource['+ sourceCounter++ +']" value="" placeholder="Discovery Source" /></label> Remove</p>').appendTo(dataSourceField);
i++;
return false;
});
$('#sign-up-organization-discovery-source').on('click', '.remove', function() {
if (i > 1) {
$(this).parent('p').remove();
i--;
}
return false;
});
});
</script>
</body>
To answer the last comment, I need to be able to make the code more readable, so I'm posting it here in a new answer.
Having thought about it a little more, it would make more sense to add it as custom 'getter' function. I'll also include the 'instanceMethods' to demonstrate how that works, as well.
var Organization = sequelize.define('organization', {
...
},{
freezeTableName: true,
classMethods: {
associate: function(db) {
Organization.belongsToMany(db.User, { through: 'member', foreignKey: 'user_id' });
},
},
// Here's where custom getters would go
getterMethods: {
discoverySources: function() {
return this.getDataValue('discoverySource');
}
},
// here's the instance methods
instanceMethods: {
getSourcesArray: function() {
return this.getDataValue('discoverySource');
}
}
});
Both of these options add the functions to each instance created by the Model. The main difference being in how they are accessed.
organization.discoverySources; // -> ['s1', 's2', etc...]
organization.getSourcesArray(); // -> ['s1', 's2', etc...]
note the additional () required on the instanceMethod. Those are added as functions of the instance, the getterMethods get added as properties.
setterMethods work the same way to allow you to define custom setters.
Hope that clarifies things a bit.

Categories