I am trying to get user input from a form to update onto a webpage. I have recently found out that JSON.stringify does not take html ID elements and that in order to do so they would need to be converted. I have found a guide here but did not help. If anyone has any ideas please let me know, I would truly appreciate it :D
let type = document.getElementById('Type');
let html = type.outerHTML;
let typeData = {
html: html
};
let name = document.getElementById('Name');
let html = name.outerHTML;
let nameData = {
html: html
};
let quantity = document.getElementById('quantity');
let html = quantity.outerHTML;
let quanData = {
html: html
};
update.addEventListener('click', _ => {
fetch('/Plants', {
method: 'put',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: typeData,
name: nameData,
quantity: quanData
})
})
.then(res => {
if (res.ok) return res.json()
})
.then(response => {
window.location.reload(true)
})
})
server.js file where all my put route is
app.put('/Plants', (req, res) => {
quoteCollection.findOneAndUpdate(
{ type: req.body.type },
{
$set: {
quantity: req.body.quantity,
type: req.body.type,
name: req.body.name
}
}
)
.then(result => {res.json('Success')})
.catch(error => console.error(error))
});
});
<h2>Update an item</h2>
<form id="inventory-form">
<input type="text" placeholder="Type" name="Type" id="Type" />
<input type="text" placeholder="Name" name="Name" id="Name" />
<input type="number" placeholder="quantity" name="quantity" id="quantity" />
<button id="update-button " type="submit">Submit</button>
</form>
Use formData and do not use the click event but the form submit event:
document.getElementById("inventory-form").addEventListener("submit", function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('/Plants', {
method: 'put',
body: formData
})
.then(res => {
if (res.ok) return res.json()
})
.then(response => {
// window.location.reload(true) // WHY???
})
})
<h2>Update an item</h2>
<form id="inventory-form">
<input type="text" placeholder="Type" name="Type" id="Type" />
<input type="text" placeholder="Name" name="Name" id="Name" />
<input type="number" placeholder="quantity" name="quantity" id="quantity" />
<button id="update-button" type="submit">Submit</button>
</form>
But WHY reload the page?
Or if you need to refresh WHY use fetch?
Related
I've tried quite a few things and read a lot of examples of using the data returned by Fetch as an object to put into a table or similar but I can't seem to get it. The following code authorises the Strava user to use my test App and then gets the Users last 30 activities. Once data is returned as a Promise I can view it in the console, but not use it. I'm a bit of a novice so just need some direction on how to use this data in table.
//my code is below
<script>
//reAuthorize Click
function Authorize() {
document.location.href = "https://www.strava.com/oauth/authorize?client_id=XXX&redirect_uri=https://localhost:44370/strava/index&response_type=code&scope=activity:read_all"
}
const codeExchangeLink = `https://www.strava.com/api/v3/oauth/token`
function codeExchange() {
fetch(codeExchangeLink, {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({
client_id: '#ViewBag.cId',
client_secret: '#ViewBag.cSec',
code: '#ViewBag.code',
//need to do this to get a new refresh token that 'reads all' and issues a new Access Token - refer to comments below
grant_type: 'authorization_code'
})
})
.then(res => res.json())
.then(res => getActivities(res))
}
// getActivities
const auth_link = "https://www.strava.com/oauth/token"
function getActivities(res) {
var obj;
const activities_link = `https://www.strava.com/api/v3/athlete/activities?access_token=${res.access_token}`
fetch(activities_link)
.then((res) => console.log(res.json()))
}
</script>
<form asp-action="Index" method="get">
<input type="text" id="cId" value="#ViewBag.cId" />
<input type="text" id="cSec" value="#ViewBag.cSec" />
<input type="text" id="rT" value="#ViewBag.rT" />
<input type="text" id="code" value="#ViewBag.code" />
<input type="text" id="test" />
</form>
<input type="button" onclick="Authorize()" value="ReAuthorise" />
<input type="button" onclick="codeExchange()" value="Get Activities" />
// After help from #Barmar i have made the following changes to the getActivities function. I have then tried to populate the table with the following code with no luck
async function getActivities(res) {
const activities_link = `https://www.strava.com/api/v3/athlete/activities?access_token=${res.access_token}`
await fetch(activities_link)
/* .then((res) => console.log(res.json()))*/
.then((res) => res.json())
.then(data => populateTable(data));
}
function populateTable(data) {
for (var i = 0; i < data.length; i++) {
// create a new row
var newRow = table.insertRow(data.length);
for (var j = 0; j < data[i].length; j++) {
// create a new cell
var cell = newRow.insertCell(j);
// add value to the cell
cell.innerHTML = data[i][j];
}
}
}
res.json() returns a promise, you need to use .then() to get the result, just like you did in codeExchange()
function getActivities(res) {
const activities_link = `https://www.strava.com/api/v3/athlete/activities?access_token=${res.access_token}`
fetch(activities_link)
.then((res) => res.json())
.then(data => console.log(data));
}
If you want to populate a table from it, call the function that does that in place of console.log(data).
I found the answer that I was looking for - Working code is included below (this authrorises the Strava User and populates a table with their 30 most recent activities):
<script>
//reAuthorize Click
function Authorize() {
document.location.href = "https://www.strava.com/oauth/authorize?client_id=XXX&redirect_uri=https://localhost:44370/strava/index&response_type=code&scope=activity:read_all"
}
const codeExchangeLink = `https://www.strava.com/api/v3/oauth/token`
function codeExchange() {
fetch(codeExchangeLink, {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({
client_id: '#ViewBag.cId',
client_secret: '#ViewBag.cSec',
code: '#ViewBag.code',
//need to do this to get a new refresh token that 'reads all' and issues a new Access Token - refer to comments below
grant_type: 'authorization_code'
})
})
.then(res => res.json())
.then(res => getActivities(res))
}
// getActivities
const auth_link = "https://www.strava.com/oauth/token"
async function getActivities(res) {
const activities_link = `https://www.strava.com/api/v3/athlete/activities?access_token=${res.access_token}`
await fetch(activities_link)
.then((res) => res.json())
.then(data => populateTable(data));
}
function populateTable(data) {
for (var i = 0; i < data.length; i++) {
var table = "";
for (var i in data) {
table += "<tr>";
table += "<td>"
+ data[i].name + "</td>"
+ "<td>" + data[i].distance + "</td>"
+ "<td>" + data[i].average_heartrate + "</td>"
+ "<td>" + data[i].moving_time + "</td>";
table += "</tr>";
}
document.getElementById("table").innerHTML = table;
}
}
</script>
<form asp-action="Index" method="get">
<input type="text" id="cId" value="#ViewBag.cId" />
<input type="text" id="cSec" value="#ViewBag.cSec" />
<input type="text" id="rT" value="#ViewBag.rT" />
<input type="text" id="code" value="#ViewBag.code" />
<input type="text" id="test" />
</form>
<input type="button" onclick="Authorize()" value="ReAuthorise" />
<input type="button" onclick="codeExchange()" value="Get Activities" />
<nav class="navbar navbar-default">
</nav>
<div class="col-md-3"></div>
<div class="col-md-6 well">
<hr style="border-top:1px dotted #ccc;" />
<div class="col-md-8">
<table class="table table-bordered">
<thead class="alert-info">
<tr>
<th>Activity Name</th>
<th>Distance</th>
<th>Heart Rate</th>
<th>Time</th>
</tr>
</thead>
<tbody id="table"></tbody>
</table>
</div>
</div>
Any help appreciated. I've got an app that pulls data from google books api. From each book page, the user is able to leave a review. The path to the review is /review/${isbn Number}. Each page has a path based on the isbn. The review routes work and I'm able to make the post request through insomnia/postman with no issues, I'm just having trouble with the front-end js in pulling the data from the input boxes to make the post request. I'm not sure if the issue is because the isbn being in the path. Below is my front-end javascript that I am unable to fix.
const newFormHandler = async (event) => {
event.preventDefault();
console.log("testing")
const description = document.querySelector('#description').value;
const reviewTitle = document.querySelector('#reviewTitle').value;
const isbn = window.location.search
if (description) {
const response = await fetch(`api/review/${isbn}`, {
method: 'POST',
body: JSON.stringify({ description, reviewTitle }),
headers: {
'Content-Type': 'application/json',
},
});
if (response.ok) {
document.location.reload();
} else {
alert('Failed to create review');
}
}
};
document
.querySelector('.form-group')
.addEventListener('submit', newFormHandler);
My form is below:
<div class="col form-group">
<div class ="card reviewCard" style = "background-color:#fcf8f3; color: #65625e;">
<form id="blog-form">
<div>
<label for="reviewTitle">Review Title</label>
<input
value="{{title}}"
id="reviewTitle"
name="reviewtitle"
placeholder="Enter Review Title"
type="text"
required="required"
class="form-control"
data-bv-notempty="true"
data-bv-notempty-message="The title cannot be empty"
/>
</div>
<div>
<label for="review">Review</label>
<textarea
id="description"
name="review"
cols="40"
rows="10"
required="required"
class="form-control"
>{{description}}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
And here is my route that works fine with insomnia, no issues.
router.get('/review/:id', async (req, res) => {
try {
const isbn13 = req.params['id'];
const reviewData = await Review.findAll({ where: {
isbn:isbn13
},
include: [
{
model: User,
attributes: ['name'],
}
]
})
const reviews = reviewData.map((review) => review.get({ plain:true}));
// console.log(isbn13);
res.render('review', {
isbn: isbn13, reviews:reviews
});
} catch (err) {
console.log(err)
}
});
Any help appreciated. I tried to pull in the isbn number from the path, but with no success. I think I have it formatted wrong somehow.
First console log your req
You should see the body containing some data.
In a get request the they are arguments in the URL.
In a Psot request they are in the body of the request.
I am having issues with a put request that seems to hang on the client side. The PUT request successfully updates the data on the server side, but it does not do anything else within a $.ajax().done() function nor in a success: function(result){} function.
The $('#update').click(function (){} is supposed to get the name and description inputs from the HTML front end, utilize the $.ajax() function to submit the put request, utilize the router.put() to submit the data to the controller
I think I'm missing something small but crucial. any assistance is appreciated. thank you!
HTML
<h1>Project Details</h1>
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroup-sizing-default">ID</span>
<input
type="text"
class="form-control"
name="id"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-default"
value="<%= project.id %>"
disabled
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroup-sizing-default">Created Date</span>
<input
type="text"
class="form-control"
name="createdDate"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-default"
value="<%= project.createdDate %>"
disabled
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroup-sizing-default">Last Updated Date</span>
<input
type="text"
class="form-control"
name="lastUpdated"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-default"
value="<%= project.lastUpdated %>"
disabled
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroup-sizing-default">Project Name</span>
<input
id="name"
type="text"
class="form-control"
name="name"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-default"
value="<%= project.name %>"
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroup-sizing-default">Description</span>
<input
id="description"
type="text"
class="form-control"
name="description"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-default"
value="<%= project.description %>"
/>
</div>
<button id="delete" type="delete" class="btn btn-danger">DELETE</button>
<a type="cancel" class="btn btn-secondary" href="/projects">Cancel</a>
<button id="update" class="btn btn-primary float-right">Update</button>
<script>
$(document).ready(function () {
$('#update').click(function () {
var settings = {
url: 'http://localhost:3000/projects/<%= project.id %>',
method: 'PUT',
dataType: 'json',
data: { name: $('#name').val(), description: $('#description').val() },
success: function (result) {
console.log(result);
},
};
$.ajax(settings);
});
$('#delete').click(function () {
var settings = {
url: 'http://localhost:3000/projects/<%= project.id %>',
method: 'DELETE',
timeout: 0,
success: function (response) {
console.log(response);
},
};
$.ajax(settings);
});
});
</script>
Expressjs Router
const express = require('express');
const ProjectModel = require('../src/controller/projectController');
const router = express.Router();
const controller = new ProjectModel();
module.exports = (params) => {
const { projectService } = params;
// UPDATE
router.put('/:id', async (request, response) => {
await controller.updateById(request);
return response.redirect("/projects");
});
return router;
};
Mongoose MongoDB Controller
const mongoose = require('mongoose');
const projectModel = require('../model/projectModel');
const { ProjectSchema } = require('../model/projectModel');
const Project = mongoose.model('projects', ProjectSchema);
class ProjectModel {
constructor() {
this.Project = Project;
}
async updateById(request) {
const { name, description } = request.body;
const { id } = request.params;
const query = { _id: request.params.id };
const options = { new: true };
const update = { name: name, description: description, lastUpdated: Date.now() };
let result = await this.Project.findByIdAndUpdate(query, { $set: update }, options);
console.log(result);
}
}
module.exports = ProjectModel;
I needed to put the 303 status code in the return response.redirect();. Without the 303 status code the ajax success was never ran.
router.put('/:id', async (request, response) => {
await controller.updateById(request);
return response.redirect(303, "/projects");
});
I am doing an exercise of an online course. In this exercise I have a form with 3 inputs and I have to extract them to make a request to a server. My problem is that my JavaScript Code only returns the empty string if I log it in the console, not the changed value. I guess it's accessing the inital value of the html. How can I solve this?
JavaScript Code:
// Initial call if the form is submitted
document.querySelector("#compose-submit").onsubmit = send_mail();
// The send_mail function:
function send_mail() {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
});
return false;
Corresponding html:
<h3>New Email</h3>
<form id="compose-form">
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="submit" class="btn btn-primary" id="compose-submit"/>
</form>
In the first line when you are assigning a callback to the onsubmit event, you need to just pass the function name and not call it.
So, changing your first line of code to
document.querySelector("#compose-submit").onclick = send_mail;
or
bind your event to the form element to make it work with onsumbit event
document.querySelector("#compose-form").onsubmit = send_mail;
should work.
Here's a JSFiddle as a sample (check console)
Change your input type to button to prevent reloading the page after submitting. And you will keep your values
// Initial call if the form is submitted
document.querySelector("#compose-submit").addEventListener('click', () => {
send_mail();
});
// The send_mail function:
function send_mail() {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
console.log(recipients);
console.log(subject);
console.log(body);
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
});
return false;
}
<h3>New Email</h3>
<form id="compose-form">
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="button" value="Submit" class="btn btn-primary" id="compose-submit" />
</form>
It's because of the submit type, when you submit the form, it submits the values of the form to the given url path of your action attribute of the form <form action="path_to_fetch" method="POST"> and then refreshed the page after. So your javascript code can't catch the values of the form.
One solution is to prevent the form to be refreshed and let your javascript code do the fetching method.
so in your js code, do this:
// Initial call if the form is submitted
document.querySelector("#compose-submit").addEventListener("click", send_mail);
// The send_mail function:
function send_mail(e) {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
}).finally(() => {
document.querySelector('#compose-recipients').value = "";
document.querySelector("#compose-subject").value = "";
document.querySelector("#compose-body").value = "";
})
}
Use the finally function to empty the form after submitting the form.
EDIT:
And also change your button type to just button, using the submit type will cause the refresh.
<button class="btn btn-primary" id="compose-submit" type="button">Submit</button>
I have a problem in my image upload in Laravel Vue. I do not upload image in my project.Here is My Code
<form action="">
<input type="text" id="firstName" class="form-control" v-model="user.firstName" value="Frankie">
<input type="text" id="lastName" class="form-control" v-model="user.lastName" value="Apple">
<select v-model="user.profile.country" v-chosen="user.profile.country" class="option-select">
<option v-for="(country, key) in countries" :value="key">{{country}}</option>
</select>
<input type="file" ref="files" id="imgInp" multiple #change="selectFile">
<input type="button" class="button button__primary button__agree" value="Confirm" #click="submit">
</form>
<script>
export default {
data() {
return {
user : [],
files : [],
uploadFiles : [],
}
},
methods : {
selectFile() {
const files = this.$refs.files.files;
this.uploadFiles = [ ...this.uploadFiles, ...files];
this.files = [
...this.files,
..._.map(files, file => ({
name: file.name,
type: file.type,
size: file.size,
}))
];
},
submit() {
var data = {
'customerDetail': {
'firstName' : this.user.firstName,
'lastName' : this.user.lastName,
'address' : {
'country' : this.user.profile.country,
},
'application': {
'attachments' : this.uploadFiles,
},
},
};
const config = {
headers: { 'content-type': 'multipart/form-data' }
};
axios
.post(`/web/bookings`, data, config)
.then((e) => {
console.log(e);
})
.catch((e) => {
console.log(e);
})
},
},
}
</script>
But When I submit Data it shows error
Missing boundary in multipart/form-data POST data
If I remove config data then my image is not uploaded. I don't get where the problen is. Please help me to solve this problem. Thanks in advance