I have a vue application which inserts, updates and delete posts by using mongodb but i am having a problem with the update function. when i press the button which updates the posts i am getting the following error. note in the postComponent.vue i just added the template to show how the form is being submitted and the function in the sciprt tag updatePost
Access to fetch at 'http://localhost:5000/api/posts/5e31a39024a21d44bc4654af' from origin 'http://localhost:8080' has been blocked by CORS policy: Method UPDATE is not allowed by Access-Control-Allow-Methods in preflight response.
posts.js
//update posts
router.put('/:id', async (req,res) => {
const posts = await loadpostscollection();
await posts.updateOne({
topic: req.body.topic,
price: req.body.price,
location: req.body.location,
provider: req.body. provider,
createdAt: new Date()
});
res.status(201).send();
});
postServise.js
//update Posts
static updatePost( id, topic, price, location, provider) {
return fetch(url + id, {
method: "UPDATE",
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
body: JSON.stringify({
topic,
price,
location,
provider
}
)
});
}
postComponent.vue
<template>
<div class ="container">
<router-link to="/postComponent" >Show me post component</router-link>
<h1>Create a new course</h1>
<div class="create-post">
<label for="create-topic">Add topic: </label>
<br>
<br>
<input type="text" id="create-topic" v-model="topic" placeholder="enter" required>
<br>
<br>
<label for="create-price">Add a price: </label>
<br>
<br>
<input type="text" id="create-price" v-model="price" placeholder="enter">
<br>
<br>
<label for="create-location">Add a location: </label>
<br>
<br>
<input type="text" id="create-location" v-model="location" placeholder="enter">
<br>
<br>
<label for="create-provider">Add a provider: </label>
<br>
<br>
<input type="text" id="create-provider" v-model="provider" placeholder="enter">
<br>
<br>
<button v-on:click="insertPost">Create course</button>
</div>
<hr>
<p class="error" v-if="error">{{ error }}</p>
<div class="posts-container">
<div class="post"
v-for="(post, index) in posts"
v-bind:item="post"
v-bind:index="index"
v-bind:key="post._id">
<br>
<p>Course topic:</p>
<p class="text">{{post.topic}} </p>
<p>Course price:</p>
<p class="text"> {{post.price}} </p>
<p>Course location:</p>
<p class="text">{{post.location}} </p>
<p>Created by:</p>
<p class="text"> {{post.provider}} </p>
<button v-on:click="deletePost(post._id)">Delete course</button>
<br>
<br>
<br>
<br>
<input type="text" v-model="post.topic"/>
<input type="text" v-model="post.price"/>
<br>
<br>
<input type="text" v-model="post.location"/>
<br>
<br>
<input type="text" v-model="post.provider"/>
<button v-on:click="updatePost(post)">Update course</button>
</div>
</div>
</div>
</template>
<script>
async updatePost({ _id: id, topic, price, location, provider }) {
await postService.updatePost(id, topic, price, location, provider);
this.posts = await postService.getPosts();
},
</script>
index.js
const express = require ('express');
const bodyparser = require ('body-parser');
const cors = require ('cors');
const app = express();
app.use(bodyparser.json());
app.use(cors({ origin: '*'}));
const posts = require('./api/posts');
const users = require('./api/users');
app.use('/api/posts', posts);
app.use('/api/users', users);
const port = process.env.port || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
https://i.stack.imgur.com/75fRb.png
Is not a problem of vue or JS, it's the CORS request problem. You must to allow CROS request on backend, or change request URI to http://localhost:8080/api/posts/5e31a39024a21d44bc4654af.
Related
I have the following code but it does not post to my Subscriber collection. When I put in an email address it does not post to my subscriber collection type. Also it does not console.log
Using Nuxt3/Strapi4
<template>
<div class="relative flex justify-center w-full h-64 pb-16 mt-14 subscribe-bg">
<Container>
<div class="w-full mx-auto lg:w-3/6">
<div class="px-10 -mt-12 text-center bg-white rounded-lg shadow-xl py-9 subscribe-box">
<Heading tag="h3" font-style="h3">Subscribe</Heading>
<Heading tag="h2" font-style="h2">Never miss a planner</Heading>
<p
class="w-full px-2 mx-auto text-center pb-7 text-brand-grey-400"
>Subscribe to receice the worlds most cutting edge planner news direct to your inbox. Our newsletter is on fire.</p>
<div class="flex items-center">
<form #submit.prevent="handleSuscribe">
<input-field
id="email"
v-model="email.email"
type="email"
name="email"
placeholder="Your email"
class="w-3/4 mr-8"
/>
<Btn class="h-full" type="submit">Subscribe</Btn>
</form>
</div>
</div>
</div>
</Container>
</div>
</template>
<script setup>
import { useToast } from 'vue-toastification';
const toast = useToast();
const email = ref({ email: "" })
const handleSuscribe = async () => {
await $fetch("http://localhost:1337/api/subscribers", {
method: "POST",
body: {
data: {
email: email.value,
}
}
})
console.log(email.value)
console.log(handleSuscribe)
}
</script>
Tried to convert from the following code from Nuxt 2. It looked pretty simple at first but now I am running into issues.
<template>
<div
class="sm:flex mx-auto items-center m-10 justify-center space-x-6 sm:space-x-20 m-3 sm:m-6 mx-6"
>
<div>
<h1 class="text-lg m-7">Sign Up For NewsLetter</h1>
</div>
<div>
<form #submit="handleSuscribe">
<input
id=""
v-model="email"
class="p-2 m-3 sm:m-0 border border-solid border-t-0 border-l-0 border-r-0 border-b-1 outline-none border-black"
type="email"
name=""
placeholder="email"
/>
<button type="submit" class="button--grey">Subscribe</button>
</form>
</div>
</div>
</template>
<script>
export default {
name: 'NewsLetter',
data() {
return {
email: '',
}
},
methods: {
async handleSuscribe(e) {
e.preventDefault()
this.$swal({
title: 'Successful!',
text: 'Thanks for Subscribing',
icon: 'success',
button: 'Ok',
})
await this.$strapi.$subscribers.create({ Email: this.email })
this.email = '' // clear email input
},
},
}
</script>
I am trying to insert some data into the database through a fetch API POST request to a Next.js API route but I am getting the following two error messages in the browser's console:
api/addCompany/addCompany:1 Failed to load resource: the server responded with a status of 500 (Internal Server Error) register:1
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
These are my project's folders (it's relevant because of Next.js's routing system)
This is the component where I am doing the fetch API request (please don't judge my poor Typescript skills, I am new to it, still not finding the propper event type):
import styles from '../styles/Register.module.css'
import { NextPage } from "next"
import { prisma } from '../prisma/prisma_client';
import { Prisma } from '#prisma/client';
import { useSession } from "next-auth/react"
const Register: NextPage = () => {
const createCompany: any = async (event: any) => {
event.preventDefault()
const company: Prisma.CompanyCreateInput = {
companyName: event.target.companyName.value,
gender: event.target.gender.value,
firstName: event.target.firstName.value,
lastName: event.target.lastName.value,
street: event.target.street.value,
houseNumber: parseInt(event.target.houseNumber.value),
postcode: parseInt(event.target.postcode.value),
city: event.target.city.value,
country: event.target.country.value,
countryCode: event.target.countryCode.value,
callNumber: parseInt(event.target.callNumber.value),
emailAddress: event.target.emailAddress.value,
website: event.target.website.value,
socials: {},
companyUser: {
connect: { id: 'cl0y4y8xo0021mwtcmwlqfif6' }
}
}
const companyJSON = JSON.stringify(company)
const endpoint = '/api/addCompany/addCompany'
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: companyJSON,
}
const response = await fetch(endpoint, options)
const data = await response.json()
console.log(data)
}
return (
<form onSubmit={createCompany} className={styles.form} id="signupForm" noValidate>
<h2>Company Information</h2>
<div className="fieldWrapper">
<input type="text" id="companyName" name="companyName" placeholder=" " />
<label htmlFor="companyName">Company Name<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" list="genders" id="gender" name="gender" placeholder=" " />
<label htmlFor="gender">Gender<span>*</span></label>
<div className='errorMessage'></div>
<datalist id="genders">
<option>Female</option>
<option>Male</option>
</datalist>
</div>
<div className="fieldWrapper">
<input type="text" id="firstName" name="firstName" placeholder=" " />
<label htmlFor="firstName">First Name<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="lastName" name="lastName" placeholder=" " />
<label htmlFor="lastName">Last Name<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="street" name="street" placeholder=" " />
<label htmlFor="street">Street<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="number" id="houseNumber" name="houseNumber" placeholder=" " />
<label htmlFor="houseNumber">House Number<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="number" id="postcode" name="postcode" placeholder=" " />
<label htmlFor="postcode">Postcode<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="city" name="city" placeholder=" " />
<label htmlFor="city">City<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="country" name="country" placeholder=" " />
<label htmlFor="country">Country<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="countryCode" name="countryCode" placeholder=" " />
<label htmlFor="countryCode">Country Code<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="number" id="callNumber" name="callNumber" placeholder=" " />
<label htmlFor="callNumber">Call Number<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="email" id="emailAddress" name="emailAddress" placeholder=" " />
<label htmlFor="emailAddress">Email Address<span>*</span></label>
<div className='errorMessage'></div>
</div>
<div className="fieldWrapper">
<input type="text" id="website" name="website" placeholder=" " />
<label htmlFor="website">Website</label>
</div>
<div className="fieldWrapper">
<input type="text" id="socials" name="socials" placeholder=" " />
<label htmlFor="socials">Socials</label>
</div>
<div className="fieldWrapper">
<button type="submit">Save</button>
</div>
</form>
)
}
export default Register
And this is the the addCompany file's code which serves as the Next.js API route for my fetch API request:
import { Prisma } from '#prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from '../../../prisma/prisma_client';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const {body} = req;
const companyData: Prisma.CompanyCreateInput = JSON.parse(body);
const addCompany = await prisma.company.create({
data: companyData
})
res.status(200).json(addCompany);
}
export default handler
I appreciate any help. Thank you.
I tried to comment out
const data = await response.json() console.log(data)
in the Register component so the error "Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0" disappeared but that is no solution to the problem at all.
I also tried to adjust the route of my fetch request to any possible option because I wasn't sure how exactly Next.js autocompletes it, for example I tried: '/api/addCompany/addCompany.ts' and so on.
I expect the problem to be something small, I hope it isn't typo.
Thank you again.
PS: I also checked similar posts on this matter but couldn't find a fix for my problem.
There is no need to reparse the body data in the API endpoint because Next.js middleware convert that data to an object already:
API routes provide built in middlewares which parse the incoming
request (req). Those middlewares are:
req.cookies - An object containing the cookies sent by the request. Defaults to {}
req.query - An object containing the query string. Defaults to {}
req.body - An object containing the body parsed by content-type, or null if no body was sent
something like below should work:
import { Prisma } from '#prisma/client';
import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from '../../../prisma/prisma_client';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const {body: companyData} = req;
//const companyData: Prisma.CompanyCreateInput = JSON.parse(body);<- No need to reparse the data here
const addCompany = await prisma.company.create({
data: companyData
})
res.status(200).json(addCompany);
}
export default handler
Thanks to this answer here for clarification.
when i click on EDIT button to send the form data ,insted of displaying the editted text ,it displays blank field and NULL is send to the database.
i have correctly used
app.use(express.json());
app.use(express.urlencoded({extended: true}));
this problem is only there for PUT request.POST is working fine.
Can anyone please help me ?
i am using PERN stack and have made a restful API .this is the route for Updating a field:
app.put('/placements/announcements/:id',async(req,res)=>{
try{
const {id}=req.params;
const {editPost,title}=req.body;
const updatePost= await pool.query("update announcements set an_desc=$1,an_title=$2 where an_id=$3 returning *",[editPost,title,id]);
res.json("updated");
}catch(err){
console.error(err.message);
}
});
here is the form:
<Modal
size="lg"
show={lgShow}
onHide={() => setLgShow(false)}
aria-labelledby="example-modal-sizes-title-lg"
id={`id${p.an_id}`}
>
<Modal.Header closeButton>
<Modal.Title id="example-modal-sizes-title-lg">
{p.an_title}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<form onSubmit={updatePost}>
<div className="form-group">
<textarea className="form-control"
id="exampleFormControlTextarea1"
rows="3"
value={editPost}
onChange={e=>setEditPost(e.target.value)}
name="editPost"
>
</textarea>
<input type="text" value={title} onChange={e=>setTitle(e.target.value)} />
<button type="submit" value="Submit" className="btn btn-primary mt-2 float-end ">
Edit
</button>
</div>
</form>
</Modal.Body>
</Modal>
<textarea className="form-control"
id="exampleFormControlTextarea1"
rows="3"
value={editPost}
onChange={e=>setEditPost(e.target.value)}
name="editPost"
>
</textarea>
<input type="text" value={title} onChange={e=>setTitle(e.target.value)} />
<button type="submit" value="Submit" className="btn btn-primary mt-2 float-end ">
Edit
</button>
</div>
</form>
</Modal.Body>
</Modal>
and this is the update function:
const EditPost=({p,category})=>{
const [lgShow, setLgShow] = useState(false);
const [editPost,setEditPost]= useState(p.an_desc);
const [title,setTitle]=useState(p.an_title);
const updatePost= async e=>{
e.preventDefault();
try{
const body={editPost,title};
const response= await fetch(`http://localhost:5000/${category}/announcements/${p.an_id}`,{
method:"PUT",
header:{"Content-Type":"application/json"},
body: JSON.stringify(body)
})
window.location=`${category}`;
console.log("updated");
}catch(err){
console.error(err.message);
}
}
I am using vue form to edit one item, but I cannot conclude in which method should I assign a values to categoryName and description to make those values appear in form?
I tried to make axios call and assign response to categoryName and description in the methods: created, mounted, beforeMouned, but it does not show values of categoryName and description in input fields, although values are obtained from the backend. Also v-model.lazy does not give results.
This is my code:
<template>
<div class="pt-5">
<form #submit.prevent="submitCategory">
<div class="form-group">
<label for="categoryName">Category name</label>
<input v-model.lazy="categoryName" value="categoryName" type="text" class="form-control" id="categoryName" aria-describedby="categoryNameHelp" placeholder="Enter category name">
</div>
<br>
<div class="form-group">
<label for="description">Description</label>
<input v-model="description" type="text" class="form-control" id="description" placeholder="Enter description">
</div>
<br>
<button type="submit" class="btn btn-primary mt-2">Submit</button>
</form>
</div>
</template>
<script>
export default {
name: "EditCategory",
data() {
return {
categoryName: '',
description: '',
}
},
beforeMount () {
this.$axios.get(`/api/categories/${this.$route.params.id}`,{
id: this.$route.params.id
}).then((response) => {
console.log(response.data)
this.categoryName = response.categoryName;
this.description = response.description;
}); },
methods: {
submitCategory() {
this.$axios.post('/api/categories', {
categoryName: this.categoryName,
description: this.description,
}).then(response => {
console.log(response)
this.$router.push({name: 'Categories'});
})
},
initialize () {
},
},
}
</script>
<style scoped>
</style>
Axios Response object
When we send a request to a server, it returns a response. The Axios response object consists of:
data - the payload returned from the server
status - the HTTP code returned from the server
headers - headers sent by server
You did console.log(response.data) in BeforeMount Hook. You will get your required data under response.data object
this.categoryName = response.data.categoryName;
this.description = response.data.description;
I tried these ... none of them worked, any hints pls ...
this.title = 'Diagnostic Tools';
it('should have a title', function() {
browser.driver.get('https://URL');
browser.ignoreSynchronization = true;
browser.driver.findElement(by.id('username')).sendKeys('user');
browser.driver.findElement(by.id('password')).sendKeys('pass123');
browser.driver.findElement(by.name('login')).click();
browser.waitForAngular();
expect(browser.getTitle()).toContain('Diagnostic Tools');
element(by.linkText("TOOLS")).click();
element(by.name('server_ip')).sendKeys('1.1.1.1');
});
});
Tried 3 ways after clicking "TOOLS". Adding sleep btw click & send also didn't help.
element(by.name('server_ip')).sendKeys('1.1.1.1');
element(by.cssContainingText('input[name="server_ip"]')).sendKeys('1.1.1.1');
element(by.css('server_ip')).sendKeys('1.1.1.1');
Input class:
<i><div class="form-group required ng-scope" ng-repeat="(param_key, param_value) in selectedTool.params">
<label class="col-sm-2 control-label ng-binding">IP (s)</label>
<div class="col-sm-4">
<input style="" required="required" pattern="[ ]*((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})( (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})*[ ]*"
class="form-control ng-valid-pattern ng-valid-maxlength ng-dirty ng-valid-parse ng-valid ng-valid-required ng-touched"
name="server_ip" ng-model="toolInput[param_key]" ng-required="true" ng-attr-pattern="{{param_value.pattern}}" ng-attr-type="{{param_value.type}}" ng-attr-min="{{param_value.min}}" ng-attr-max="{{param_value.max}}" ng-attr-maxlength="{{param_value.maxlength}}">
</div>
<div class="col-sm-6">
<span class="help-block ng-binding">Can be multiple space separated ips.</span>
</div>
You need to explicitly wait for the element to be visible prior to sending keys:
var EC = protractor.ExpectedConditions;
var serverIP = element(by.name("server_ip"));
browser.wait(EC.visibilityOf(serverIP), 5000);
serverIP.sendKeys("1.1.1.1");