我有一个简单的后端代码,与Rest API很好地工作
更新代码ClientSchema.js
const mongoose = require('mongoose');
var Schema = mongoose.Schema;
const customerSchema = new Schema({
paymentReferenceCode:{
type: String,
required: true
},
paymentType:{
type: String,
required: true
},
paymentDescription:{
type: String,
required: true
},
procedureAmount:{
type: String,
required: true
},
paymentDiscount:{
type: Number,
required: true
},
AmountPaid:{
type: Number,
required: true
},
Total:{
type: Number,
required: true
},
clientdetails: {
ref: 'Client',
type: mongoose.Schema.Types.ObjectId
},
}, { timestamps: true })
module.exports = mongoose.model('Customer',customerSchema);
Client.js
const mongoose = require('mongoose');
const ClientSchema = new mongoose.Schema({
fullName:{
type:String,
required: true
},
dateofBirth:{
type:Date,
required: true
},
gender:{
type:String,
required: true
},
nationality:{
type:String,
required: true
},
address:{
type:String,
required: true
},
date:{
type:Date,
default:Date.now
}
});
module.exports = mongoose.model('Client', ClientSchema)
Router.js
router.post("/addbill",async(req,res)=>{
try {
console.log(req.params);
const clientid = await clients.findOne({ _id: req.params.id });
await new Customer({
clientdetails:clientid,
paymentReferenceCode:req.body.paymentReferenceCode,
paymentType:req.body.paymentType,
paymentDescription:req.body.paymentDescription,
procedureAmount:req.body.procedureAmount,
paymentDiscount:req.body.paymentDiscount,
AmountPaid:req.body.AmountPaid,
Total:req.body.Total
}).save(async (err, data) => {
if (err) {
console.log('err:', err);
res.status(500).json({
message: 'Something went wrong, please try again later.'
});
} else {
res.status(200).json({
message: 'Bill Created',
data,
id: data._id
});
}
});
} catch (error) {
res.status(422).json(error);
}
})
router.get('/', async (req, res) => {
try{
const data = await clients.find();
res.json(data)
}
catch(error){
res.status(500).json({message: error.message})
}
})
前端
Billing.js
import React, {Component } from "react";
import "bootstrap/dist/css/bootstrap.min.css"
import axios from "axios"
import SimpleReactValidator from "simple-react-validator"
import TextField from '@mui/material/TextField';
import $ from 'jquery'
import Select,{components} from "react-select";
import Box from '@mui/material/Box';
import NativeSelect from "@mui/material/NativeSelect";
import Button from "@mui/material/Button";
class Billing extends Component {
constructor(){
super()
this.state = {
clientdetails :{},
paymentReferenceCode: "",
paymentType: "",
paymentDescription: "",
procedureAmount: "",
paymentDiscount: "",
AmountPaid: "",
Total: "",
}
this.changePaymentReferenceCode = this.changePaymentReferenceCode.bind(this)
this.changePaymentType = this.changePaymentType.bind(this)
this.changePaymentDescription = this.changePaymentDescription.bind(this)
this.changeProcedureAmount = this.changeProcedureAmount.bind(this)
this.changePaymentDiscount = this.changePaymentDiscount.bind(this)
this.changeAMountPaid = this.changeAMountPaid.bind(this)
this.changeTOtal = this.changeTOtal.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
changePaymentReferenceCode(event){
this.setState({
paymentReferenceCode:event.target.value
})
}
changeProcedureAmount(event){
this.setState({
procedureAmount:event.target.value
})
}
changePaymentType(event){
this.setState({
paymentType:event.target.value
})
}
changePaymentDescription(event){
this.setState({
paymentDescription:event.target.value
})
}
changePaymentAmount(event){
this.setState({
paymentAmount:event.target.value
})
}
changePaymentDiscount(event){
this.setState({
paymentDiscount:event.target.value
})
}
changeAMountPaid(event){
this.setState({
AmountPaid:event.target.value
})
}
changeTOtal(event){
this.setState({
Total:event.target.value
})
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
})
}
componentDidMount(){
this.loadData();
}
loadData = () => {
axios.get('http://localhost:4000/clients', {
headers: {"Access-Control-Allow-Origin": true,
'Access-Control-Allow-Credentials' : true,
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,PATCH,OPTIONS',
crossorigin : true,
},
responseType : 'json'
})
.then((result) => {
console.log(result.data);
this.setState({
clients : result.data,
})
})
.catch((error) => {
console.log(error);
})
}
customFilter = (option, searchText) => {
if(
option.data.fullName.toLowerCase().includes(searchText.toLowerCase())
)
return true;
return false;
}
handleSubmit(event){
event.preventDefault()
const entry = {
paymentReferenceCode: this.state.paymentReferenceCode,
paymentType: this.state.paymentType,
paymentDescription: this.state.paymentDescription,
procedureAmount: this.state.procedureAmount,
paymentDiscount: this.state.paymentDiscount,
AmountPaid: this.state.AmountPaid,
Total: this.state.Total,
}
axios.post('http://localhost:4000/Bill/addbill', entry)
.then(response => {
this.setState({clientdetails: response.data})
console.log(response.data)
})
this.setState({
clientdetails:{},paymentReferenceCode: "",paymentType: "",paymentDescription: "",procedureAmount: "",
paymentDiscount: "",AmountPaid: "",Total: "",
})}
render() {
const displayNone = { display: 'none' }
return (
<div>
<div className="container">
<div className="form-div">
<p className="text-capitalize">Billing</p>
<Box component="form" onSubmit={this.handleSubmit} noValidate sx={{ mt: 1}}>
<Select
closeMenuOnSelect={true}
hideSelectedOptions={true}
options={this.state.clientdetails}
filterOption = {this.customFilter}
isClearable={true}
search={true}
components={{IndicatorSeparator: () => null,}}
placeholder={'Select Client'}
getOptionLabel={option => `${option.fullName} ${option._id}`}
onchange={this.customFilter}
></Select>
<TextField
margin="normal"
fullWidth
id="paymentReferenceCode"
label="PaymentRefernceCode"
name="paymentReferenceCode"
autoComplete="off"
value={this.state.paymentReferenceCode}
onChange={this.handleChange}
autoFocus
/>
<NativeSelect
fullWidth
onChange={this.handleChange}
value={this.state.paymentType}
inputProps={{
name: 'paymentType',
id: 'paymentType',
}}
>
<option >PaymentType</option>
<option value="Cash">Cash</option>
<option value="PayPal">PayPal</option>
<option value="MasterCard">MasterCard</option>
</NativeSelect>
<TextField
margin="normal"
fullWidth
InputLabelProps={{style : {color : 'black'} }}
id="paymentDescription"
label="Payment Description"
name="paymentDescription"
autoComplete="paymentDescription"
onChange={this.handleChange}
value={this.state.paymentDescription}
autoFocus
/>
<TextField
margin="normal"
fullWidth
id="AmountPaid"
label="Amount Paid"
name="AmountPaid"
autoComplete="AmountPaid"
onChange={this.handleChange}
value={this.state.AmountPaid}
autoFocus
/><TextField
margin="normal"
fullWidth
id="paymentDiscount"
label="Payment Discount"
name="paymentDiscount"
autoComplete="paymentDiscount"
onChange={this.handleChange}
value={this.state.paymentDiscount}
autoFocus
/>
<TextField
margin="normal"
fullWidth
id="procedureAmount"
label="Procedure Amount"
name="procedureAmount"
autoComplete="procedureAmount"
onChange={this.handleChange}
value={this.state.procedureAmount}
autoFocus
/>
<TextField
margin="normal"
fullWidth
id="Total"
label="Total Bill"
name="Total"
autoComplete="Total"
onChange={this.handleChange}
value={this.state.Total}
autoFocus
/>
<div id='loginSuccess' className="alert alert-success" style={displayNone} role="alert">
<strong>Success! </strong>Client Bill Entered Successful.
</div>
<Button
type="submit"
fullWidth
sx={{ mt: 3, mb: 2}}
>
<span className='btn btn-warning btn-block form-control form-group'>Submit</span>
</Button>
</Box>
</div>
</div>
</div>
);
}
}
export default Billing;
我尝试使用axios。邮寄并提交表格。但是,我无法检索客户端详细信息数据到前端,特别是表单的选择部分,它返回null。但是其他的元素会被传递到后端。这是我在控制台上得到的。数据:AmountPaid: 100总:100createdAt:"2022 - 11 - 25 - t22:31:57.306z">clientdetails:空paymentDescription:"accomodation"paymentDiscount: 100paymentReferenceCode:"2345";paymentType:"Cash"procedureAmount:"3";updatedAt:"2022 - 11 - 25 - t22:31:57.306z"__v: 0_id:"6381425 db019f3f9a48047ae"[[原型]]:目标:"6381425db019f3f9a48047ae">
我想检索的clientdetails数据前端选择部分,选择一个选项,并能够提交所有的数据。谢谢你
您在前端和后端都有一些问题。
试着像这样改变你的组件:
class Billing extends Component {
constructor() {
super();
this.state = {
clients: [],
clientdetails: '',
paymentReferenceCode: '',
paymentType: '',
paymentDescription: '',
procedureAmount: '',
paymentDiscount: '',
AmountPaid: '',
Total: '',
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleChangeClientDetails = this.handleChangeClientDetails.bind(this);
}
componentDidMount() {
this.loadData();
}
handleChange(event) {
this.setState({
...this.state,
[event.target.name]: event.target.value,
});
}
handleChangeClientDetails(newValue) {
this.setState({
...this.state,
clientdetails: newValue._id
})
}
loadData = () => {
axios
.get('http://localhost:4000/clients', {
headers: {
'Access-Control-Allow-Origin': true,
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
crossorigin: true,
},
responseType: 'json',
})
.then((result) => {
console.log(result.data);
this.setState({
...this.state,
clients: result.data,
});
})
.catch((error) => {
console.log(error);
});
};
customFilter = (option, searchText) => {
if (option.data.fullName.toLowerCase().includes(searchText.toLowerCase()))
return true;
return false;
};
handleSubmit(event) {
event.preventDefault();
const entry = {
paymentReferenceCode: this.state.paymentReferenceCode,
paymentType: this.state.paymentType,
paymentDescription: this.state.paymentDescription,
procedureAmount: this.state.procedureAmount,
paymentDiscount: this.state.paymentDiscount,
AmountPaid: this.state.AmountPaid,
Total: this.state.Total,
};
if (!this.state.clientdetails) {
console.log('Select client');
return;
}
axios.post(`http://localhost:4000/Bill/addbill/${this.state.clientdetails}`, entry).then((response) => {
console.log(response.data);
});
this.setState({
clientdetails: '',
paymentReferenceCode: '',
paymentType: '',
paymentDescription: '',
procedureAmount: '',
paymentDiscount: '',
AmountPaid: '',
Total: '',
});
}
render() {
const displayNone = { display: 'none' };
return (
<div>
<div className='container'>
<div className='form-div'>
<p className='text-capitalize'>Billing</p>
<Box
component='form'
onSubmit={this.handleSubmit}
noValidate
sx={{ mt: 1 }}
>
<Select
closeMenuOnSelect={true}
hideSelectedOptions={true}
options={this.state.clients}
filterOption={this.customFilter}
isClearable={true}
search={true}
components={{ IndicatorSeparator: () => null }}
placeholder={'Select Client'}
getOptionLabel={(option) => `${option.fullName} ${option._id}`}
onChange={this.handleChangeClientDetails} />
...
</div>
</div>
</div>
);
}
}
export default Billing;
并将参数添加到POST路由:
router.post("/addbill/:id", ... );
在你的路由器上,你正在使用req.params.id
,但它从未声明过,因为你的clientdetails
使用clientid
,它将是null
。很容易修复
router.post("/addbill",async(req,res)=>{
try {
console.log(req.params);
const clientid = await clients.findOne({ _id: req.params.id });
应该
// /-- req.params.id
router.post("/addbill/:id",async(req,res)=>{
try {
console.log(req.params);
const clientid = await clients.findOne({ _id: req.params.id });
只要记住现在你的路由将需要最后的/clientid