Need help getting Nuxt 3 form to post emails to my Strapi 4 Subscriber collection - forms

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>

Related

Why am I getting "500 (Internal Server Error)" and "Uncaught (in promise) SyntaxError: Unexpected token < "?

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.

why PUT request is sending NULL value to sql database

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);
}
}

How to prefill data in vue form?

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;

Form reset issue after get response via API in react js

I am submitting form via redux API call and getting response but on success response I am trying to reset form but that giving issue -
setState(...): Cannot update during an existing state transition (such as withinrenderor another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to 'componentWillMount'.
here is my from file -
=========================
import React from 'react';
import DefaultLayout from '../Layout/DefaultLayout';
//import $ from 'jquery';
import { connect } from 'react-redux';
import { contactRequest } from '../actions/signupActions';
import { bindActionCreators } from 'redux';
import validator from 'validator';
class Contactus extends React.Component {
constructor(props){
super(props);
document.title = "Contact Us";
this.errorMapping = {"100": "Your message has been submitted.",
"102": "Name cannot be empty.",
"104": "Email cannot be empty.",
"103": "Hotel cannot be empty.",
"105": "Incorrect email format.",
"106": "Phone cannot be empty."}
this.state = {name: '',email:'',message :''};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.baseState = this.state
}
handleInputChange(event) {
this.setState({ [event.target.name]: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
this.props.contactRequest(this.state);
}
render(){
const style_1 = {height: '240px'};
const style_2 = {marginRight: '15px'};
const style_3 = {width: 'auto'};
return(
<DefaultLayout>
<section id="content">
<div className="content-wrap">
<div className="container clearfix">
<div className="col-md-6 bottommargin">
<section id="google-map" className="gmap" style={style_1} ></section>
</div>
<div className="col-md-6">
Click here to Send an Email
Send an Email
<div className="modal fade" id="contactFormModal" tabIndex="-1" role="dialog" aria-labelledby="contactFormModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-body">
<div className="contact-widget">
<div className="contact-form-result">
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
return <span key={idx} id="succ_msg">{this.errorMapping[msg]}</span>
} else {
return <span key={idx} id="err_msg">{this.errorMapping[msg]}</span>
}
})
}
</div>
<form className="nobottommargin" id="r_contactform" name="r_contactform" method="post" onSubmit={this.handleSubmit} ref={(el) => this.myFormRef = el} >
<div className="form-process"></div>
<div className="col_half">
<label htmlFor="template-contactform-name">Name <small>*</small></label>
<input type="text" id="template-contactform-name" name="name" value={this.state.name} className="sm-form-control required" onChange={this.handleInputChange} />
</div>
<div className="col_half col_last">
<label htmlFor="template-contactform-email">Email <small>*</small></label>
<input type="email" id="template-contactform-email" name="email" value={this.state.email} className="required email sm-form-control" onChange={this.handleInputChange} />
</div>
<div className="clear"></div>
<div className="clear"></div>
<div className="col_half">
<label htmlFor="template-contactform-message">Message <small>*</small></label>
<textarea className="required sm-form-control" id="template-contactform-message" name="message" value={this.state.message} rows="6" cols="30" onChange={this.handleInputChange}></textarea>
<span className={this.state.messageError ? 'help-block error': '' }>{ this.state.messageError ? this.state.messageError: '' }</span>
</div>
<div className="col_full">
<button className="button button-3d nomargin" type="submit" id="contactform-submit" name="contactform-submit">Send Message</button>
</div>
</form>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</DefaultLayout>
);
}
}
function mapStateToProps(state){
console.log("View data :"+JSON.stringify(state.Contactdata));
return {
resultMessage: state.Contactdata
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({contactRequest: contactRequest}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps) (Contactus);
getting response in mapStateToProps function and trying to update state where I have applied condition if(msg === 100) .
Please let me know where I am doing wrong.
thanks
The right place to setState is not in the map function, since you are receiving props from redux, you can do it in the componentWillReceiveProps fucntion
class Contactus extends React.Component {
constructor(props){
super(props);
document.title = "Contact Us";
this.errorMapping = {"100": "Your message has been submitted.",
"102": "Name cannot be empty.",
"104": "Email cannot be empty.",
"103": "Hotel cannot be empty.",
"105": "Incorrect email format.",
"106": "Phone cannot be empty."}
this.state = {name: '',email:'',message :''};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.baseState = this.state
}
componentWillReceiveProps(nextProps) {
nextProps.resultMessage.status.forEach((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
}
}
}
handleInputChange(event) {
this.setState({ [event.target.name]: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
this.props.contactRequest(this.state);
}
render(){
const style_1 = {height: '240px'};
const style_2 = {marginRight: '15px'};
const style_3 = {width: 'auto'};
return(
<DefaultLayout>
<section id="content">
<div className="content-wrap">
<div className="container clearfix">
<div className="col-md-6 bottommargin">
<section id="google-map" className="gmap" style={style_1} ></section>
</div>
<div className="col-md-6">
Click here to Send an Email
Send an Email
<div className="modal fade" id="contactFormModal" tabIndex="-1" role="dialog" aria-labelledby="contactFormModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-body">
<div className="contact-widget">
<div className="contact-form-result">
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
return <span key={idx} id="succ_msg">{this.errorMapping[msg]}</span>
} else {
return <span key={idx} id="err_msg">{this.errorMapping[msg]}</span>
}
})
}
</div>
<form className="nobottommargin" id="r_contactform" name="r_contactform" method="post" onSubmit={this.handleSubmit} ref={(el) => this.myFormRef = el} >
<div className="form-process"></div>
<div className="col_half">
<label htmlFor="template-contactform-name">Name <small>*</small></label>
<input type="text" id="template-contactform-name" name="name" value={this.state.name} className="sm-form-control required" onChange={this.handleInputChange} />
</div>
<div className="col_half col_last">
<label htmlFor="template-contactform-email">Email <small>*</small></label>
<input type="email" id="template-contactform-email" name="email" value={this.state.email} className="required email sm-form-control" onChange={this.handleInputChange} />
</div>
<div className="clear"></div>
<div className="clear"></div>
<div className="col_half">
<label htmlFor="template-contactform-message">Message <small>*</small></label>
<textarea className="required sm-form-control" id="template-contactform-message" name="message" value={this.state.message} rows="6" cols="30" onChange={this.handleInputChange}></textarea>
<span className={this.state.messageError ? 'help-block error': '' }>{ this.state.messageError ? this.state.messageError: '' }</span>
</div>
<div className="col_full">
<button className="button button-3d nomargin" type="submit" id="contactform-submit" name="contactform-submit">Send Message</button>
</div>
</form>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</DefaultLayout>
);
}
}
This is the reason, you are doing setState inside render method:
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
.....
When msg==100 will be true, you are doing setState, again it will trigger re-rendering, again setState ....... infinite loop.
Remove that setState it will work.
Use componentWillReceiveProps lifecycle method, and do the setState inside that.
componentWillReceiveProps(newProps) {
newProps.resultMessage.status.forEach((msg, idx) => {
if(msg === 100) {
this.setState({
name : "",
email : ""
});
}
}
}

how do you enable/disable submit button based on form contents in Material Design Lite?

I have a submit button for a login form which is disabled by default. I want to enable it when the user enters a valid username/password. There are quite a few examples using AngularJS, JQuery, and other infrastructures but i would like to know a clean way to do it with Material Design Lite. My current code is:
class FrontPage extends Component {
constructor(props, context) {
super(props, context);
this.state = { email: '', password: '' };
}
handleEmailChange() {
this.setState({email: e.target.value})
}
handlePasswordChange() {
this.setState({password: e.target.value})
}
render() {
return(
<form className="frontpage" onSubmit={this.handleLogin}>
<div className="content-grid mdl-grid">
<div className="mdl-cell mdl-textfield mdl-js-textfield">
<input className="mdl-textfield__input" id="email" type="email" value={this.state.email} onChange={this.handleEmailChange}/>
<label className="mdl-textfield__label" htmlFor="email">email...</label>
<span className="mdl-textfield__error">Input is not an email address!</span>
</div>
<div className="mdl-cell mdl-textfield mdl-js-textfield">
<input className="mdl-textfield__input" id="password" type="password" pattern="[A-Z,a-z,0-9\?#\$%&\*\-_=+! ~\.,\/\\]*" value={this.state.password} onChange={this.handlePasswordChange}/>
<label className="mdl-textfield__label" htmlFor="password">password...</label>
<span className="mdl-textfield__error">Input can only contain letters, numbers, and some special characters!</span>
</div>
<div classname="mdl-cell">
<button className="mdl-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" type="submit" name="login" disabled>Login</button>
</div>
</div>
</form>
)
}
}
<button id='loginBtn' className="mdl-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" type="submit" name="login" disabled>Login</button>
<script>
function Enable() {
var loginBtn = document.getElementById('loginBtn');
loginBtn.removeAttribute("disabled");
componentHandler.upgradeElement(loginBtn);
}
function Disable() {
var loginBtn = document.getElementById('loginBtn');
loginBtn.setAttribute("disabled","");
componentHandler.upgradeElement(loginBtn);
}
</script>