javascript - How to submit forms using NextJS
问题描述
I am creating a product upload page for an e-commerce site using React/NextJS. Posting the form worked fine just using action='/admin/api/addproduct' in the form element, but I am struggling to get success when implementing a function to build and submit the form.
Here is the code for the upload form - AddProductForm.js:
import React, {useState} from 'react';
import { useRouter } from 'next/router'
import {Form} from 'react-bootstrap'
export default function AddProductForm({ }) {
const router = useRouter()
// userInput is for adding colours.
const [userInput, setUserInput ] = useState('');
// Form State Variables
const [id, setId] = useState('')
const [name, setName] = useState('')
const [description, setDescription] = useState('')
const [gender, setGender] = useState('')
const [price, setPrice] = useState('')
const [isOnSale, setIsOnSale] = useState('')
const [discount, setDiscount] = useState('')
const [colours, setColours ] = useState([]);
const [sizes, setSizes] = useState([])
const handleAddProduct = async event => {
event.preventDefault();
const body = new FormData()
body.append("name", name);
body.append("description", description);
body.append("gender", gender);
body.append("id", id);
body.append("price", price);
body.append("isOnSale", isOnSale);
body.append("discount", discount);
colours.forEach( (colour, index) => {
body.append(`colour-${index}`, colour)
})
const response = await fetch(
"/api/addproduct",
{
body: body,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
})
.then(response => {
alert(response['message'])
router.push("/admin/inventory")
})
.catch(error => {
console.log(error)
})
}
const handleChangeColour = (e) => {
setUserInput(e.currentTarget.value)
}
const handleRemoveColour = (e) => {
e.preventDefault();
const colourId = e.target.getAttribute("name")
setColours(colours.filter(colour => colour.id != colourId));
}
const addColour = (userInput) => {
let copy = [...colours];
setColours(copy);
copy.push({id: colours.length + 1, colour: userInput});
}
const handleAddColour = (e) => {
e.preventDefault();
addColour(userInput);
setUserInput("");
}
const handleChangeSizes = (e) => {
alert("hello")
}
return (
<Form id="add-item-form" onSubmit={handleAddProduct}>
<div className="row">
<div className ="col-lg-6">
<Form.Group className="mb-3" controlId="formProductId">
<Form.Control type="text" name="formProductId" placeholder="Enter Product Id" onChange={e => setId(e.target.value)} required/>
</Form.Group>
<Form.Group className="mb-3" controlId="formProductName">
<Form.Control name="formProductName" type="text" placeholder="Enter Product Name" onChange={e => setName(e.target.value)}required/>
</Form.Group>
<Form.Group className="mb-3" controlId="formProductGender">
<Form.Select name="formProductGender" aria-label="Gender Select" onChange={e => setGender(e.target.value)} required>
<option>Is this male, female, or both</option>
<option value="1">Male</option>
<option value="2">Female</option>
<option value="3">Unisex</option>
</Form.Select>
</Form.Group>
<Form.Group className="mb-3" controlId="formProductPrice" >
<Form.Control name="formProductPrice" type="number" placeholder="Enter Product Price" onChange={e => setPrice(e.target.value)} required/>
</Form.Group>
<Form.Group className="mb-3" controlId="formProductDiscount">
<Form.Control name="formProductDiscount" type="number" placeholder="Enter Current Discount (in %)" onChange={e => setDiscount(e.target.value)} required/>
</Form.Group>
<Form.Group className="mb-3" controlId="formProductIsOnSale">
<Form.Select name="formProductIsOnSale" aria-label="Sale Select" onChange={e => setIsOnSale(e.target.value)} required>
<option>Is this product on sale?</option>
<option value="1">Yes</option>
<option value="2">No</option>
</Form.Select>
</Form.Group>
</div>
<div className ="col-lg-6">
<Form.Group className="mb-3 " controlId="formProductDescription">
<Form.Control name="formProductDescription" type="text" placeholder="Enter Product Description" onChange={e => setDescription(e.target.value)} required/>
</Form.Group>
<Form.Group className="mb-3 " controlId="formProductSizes">
<Form.Label>Available Sizes</Form.Label>
<div className="row">
<div className="col-sm-2"></div>
<div className="col-sm-8">
<div className="row">
{['xs', 's', 'm', 'l', 'xl', 'xxl'].map(function(size, index){
return (
<div className="col" key={index}>
<Form.Check
type='checkbox'
id={`${size}-checkbox`}
name={`${size}-checkbox`}
label={`${size}`}
onChange={handleChangeSizes}
/>
</div>
)})}
</div>
</div>
<div className="col-sm-2"></div>
</div>
</Form.Group>
<Form.Group className="mb-3" controlId="formProductColours">
<div className="row">
<div className="col">
<Form.Label className="ml-5">Available Colours</Form.Label>
</div>
<div className="col">
<input value={userInput} type="text" onChange={handleChangeColour} placeholder="Enter Colour..."/>
</div>
<div className="col pb-1">
<div className="btn btn-outline-success btn-sm mb-1" onClick={handleAddColour}>+</div>
</div>
</div>
{colours.map(colour => {
return (
<>
<div className="row" key={colour.id}>
<div className="col">
<div > {colour.colour} </div>
</div>
<div className="col">
<div className="col pb-1">
<div name={colour.id} class="btn btn-outline-success btn-sm mb-1" onClick={handleRemoveColour}>-</div>
</div>
</div>
</div>
<input type="hidden" name={`colour-{colour.colour}`}></input>
</>
)
})}
</Form.Group>
</div>
</div>
<button type="submit" className="btn btn-outline-success">
Add Product
</button>
</Form>
)
}
And here is the api code addproduct.js
import {connectToDatabase} from '../../lib/mongodb'
async function addProduct(item){
const { db } = await connectToDatabase();
const resp = await db
.collection("stock")
.insertOne(item)
}
const post = async (req, res) => {
var colourList=[]
var sizeList=[]
Object.keys(req.body).forEach( key => {
if (key.substring(0,7) == "colour-"){
colourList.push(req.body[key])
}
if (key.substring(0,14) == "size-checkbox-"){
sizeList.push(key.substring(14))
}
})
// Extract Form Data
var newItem = JSON.stringify( {
id : req.body['id'],
name : req.body['name'],
description : req.body['description'],
gender : req.body['gender'],
starRating : null,
price : req.body['price'],
isOnSale : req.body['isOnSale'],
discount : req.body['discount'],
colours : colourList,
sizes : sizeList,
})
console.log(newItem)
// //add the stock to the db
// const resp = await addProduct(newItem)
res.status(201).send({ message: 'Item Added' })
return
};
export default (req, res) => {
req.method === "POST"
? post(req, res)
: req.method === "PUT"
? console.log("PUT")
: req.method === "DELETE"
? console.log("DELETE")
: req.method === "GET"
? console.log("GET")
: res.status(404).send("");
};
In the addproduct api call there is a console.log to print the new item. The output is as follows
{"starRating":null,"colours":[],"sizes":[]}
Which is also confusing, why is it only printing out those 3 attributes?
If I console.log(req.body) this is what I get
[Object: null prototype] {
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\nContent-Disposition: form-data; name': '"name"\r\n' +
'\r\n' +
'ew\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\n' +
'Content-Disposition: form-data; name="description"\r\n' +
'\r\n' +
'asdadas\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\n' +
'Content-Disposition: form-data; name="gender"\r\n' +
'\r\n' +
'1\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\n' +
'Content-Disposition: form-data; name="id"\r\n' +
'\r\n' +
'weqwe\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\n' +
'Content-Disposition: form-data; name="price"\r\n' +
'\r\n' +
'323\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\n' +
'Content-Disposition: form-data; name="isOnSale"\r\n' +
'\r\n' +
'1\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\n' +
'Content-Disposition: form-data; name="discount"\r\n' +
'\r\n' +
'32\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5\r\n' +
'Content-Disposition: form-data; name="colour-0"\r\n' +
'\r\n' +
'[object Object]\r\n' +
'------WebKitFormBoundaryrsGiVVNnm3aU1Ww5--\r\n'
}
Additionally, in the handleAddProduct function, 'const response = await fetch', I refer to response in the '.then' section, but this is not referring to the same response object declared previously and thus the message is not showing on the alert after attempting to add anitem.
解决方案
推荐阅读
- python - 如何读取文件中的行并在python中读取后取消读取
- java - 使用 JPA Hibernate 的多个多对多
- javascript - 无法访问 datamuse api 上的 JSON 数据
- python - Exporting image intensities from multiple files in multiple folders to excel in Python
- chromium - Chromium in headless mode is not getting media stream from webcam
- flutter - Flutter 是否也在 iOS 上使用 Skia 进行渲染?
- c - 对带有#define 的预处理器指令的好奇心
- node.js - Firebase 函数无法部署:SyntaxError: Unexpected token function
- python - how to remove part of url using python
- android - React Native - 具有 2 列的 FlatList 未按预期运行