Cannot read property 'files' of undefined for sending multiple images - reactjs

Code
class Add_Give_Item_Form extends Component {
constructor(props) {
super(props);
this.state = {
// #インプット情報用
info: {
name: '',
owner: '',
keyword1: '',
keyword2: '',
keyword3: '',
bland: '',
state: '未使用、新品',
category: '',
images: [],
detail: '',
},
// Validation用
//  urlは必須項目ではないのでValidationには含めない
message: {
name: '',
keyword1: '',
keyword2: '',
keyword3: '',
state: '',
category: '',
detail: '',
},
allCategory: null,
allBland: null,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleImageSelect = this.handleImageSelect(this);
}
////
...
////
handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
const { info, message } = this.state;
this.setState({
info: { ...info, [name]: value },
});
this.setState({
message: { ...message, [name]: this.validator(name, value) },
});
};
handleImageSelect = (e) => {
this.setState({
info: { ...this.state.info, images: [...this.state.info.images, e.target.files] },
});
};
render() {
const { info, message, allCategory, allBland } = this.state;
// setStateが完了するまではnullにする。
if (this.state.allCategory === null || this.state.allBland === null) {
return <CircularProgress />;
} else {
return (
<div>
///////
.....
///////
<label>Images</label>
<input type="file" multiple onChange={this.handleImageSelect} />
What I want to do
I would like to catch each file sent by a user and put into state as this.state.info.images which is an array.
I saw some questions on stackoverflow and then I found some solutions. When I wrote the same code as what I saw, I got an error like below.
cannot read property files of undefined
I should write the same code but I got the error for some reasons.
I may take another way to realize what I want to do, but I want to write readable codes and figure out why it is happening.
I would like you to teach me why this happens and solutions.
Thank you very much.

I just notice I didn't put bind with this.handleImageSelect = this.handleImageSelect(this).
Now it works well.
Thank you very much.

Related

Checkbox value in React and MongoDB

What I am seeking to accomplish is to have an optional checkbox in a form that returns false when unchecked and true when checked (in the DB).
However, whenever I view my submission in the console, things appear to be find - just not showing up in Mongo. I have attempted numerous things after searching all day both frontend and backend schema. Any help or insight would be much appreciated.
export default class CreateworkOrder extends Component {
constructor(props) {
super(props);
this.onChangeEmployee = this.onChangeEmployee.bind(this);
this.onChangeDescription = this.onChangeDescription.bind(this);
this.onChangeDuration = this.onChangeDuration.bind(this);
this.onChangeDate = this.onChangeDate.bind(this);
this.handleCheckClick = this.handleCheckClick.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
employee: '',
description: '',
duration: 0,
date: new Date(),
employees: [],
isComplete: false
}
}
componentDidMount() {
axios.get('http://localhost:5000/employees/')
.then(response => {
if (response.data.length > 0) {
this.setState({
employees: response.data.map(emp => emp.employee),
employee: response.data[0].employee
})
}
})
.catch((error) => {
console.log(error);
})
}
handleCheckClick = () => {
const complete = !this.state.isComplete;
console.log(complete);
this.setState({ complete: !this.state.isComplete});
}
Then submit below:
onSubmit(e) {
e.preventDefault();
const workOrder = {
employee: this.state.employee,
description: this.state.description,
duration: this.state.duration,
date: this.state.date,
isComplete: this.state.isComplete
}
console.log(workOrder);
axios.post('http://localhost:5000/workOrders/add', workOrder)
.then(res => console.log(res.data)).catch(console.error);
//window.location = '/home';
}
portion of the form to optionally select
<div className="form-group">
<label>Only check box if job has been completed </label>
<input name="isComplete" type="checkbox"
defaultChecked={this.state.isComplete}
onChange={this.handleCheckClick}
className="filled-in" id="filled-in-box"/>
</div>
<div className="form-group">
<input type="submit" value="Create WO" className="btn btn-primary" onSubmit={this.onSubmit}/>
</div>
</form>
DB Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const workorderSchema = new Schema({
employee: { type: String, required: true },
description: { type: String, required: true },
duration: { type: Number, required: true },
date: { type: Date, required: true },
isComplete: { type: Boolean, required: false },
},
{
timestamps: true,
});
const WorkOrder = mongoose.model('WorkOrder', workorderSchema);
module.exports = WorkOrder;
but console does show true
You are using the state variable isComplete but setting the state in complete.
this.state = {
employee: '',
description: '',
duration: 0,
date: new Date(),
employees: [],
isComplete: false
}
In handleCheckClick you are doing:
handleCheckClick = () => {
const complete = !this.state.isComplete;
console.log(complete);
this.setState({ complete: !this.state.isComplete}); }
And you are submitting workOrder which is using isComplete, which you didn't change
const workOrder = { employee: this.state.employee, description:
this.state.description, duration: this.state.duration, date:
this.state.date, isComplete: this.state.isComplete }
This should be the reason. So change the handleCheckClick like this:
handleCheckClick = () => {
let complete = !this.state.isComplete;
console.log(complete);
this.setState({ isComplete: complete});
}
Also, I noticed that you are using const keyword and then trying to change its value. const means the value shouldn't change. Use either let or var in future if you want a variable to be mutable

NextJS: Use same component in multiple routes for multiple pages

In my NextJS app, I have a search bar component OrderSearchBar.js and I want to use it in both index.js and /purchases.js pages but with different endpoints.For example,if I click search button on the index.js page,it should post form content to /orders and on the /purchases.js, form content should post to /purchaseDetails.Is there any way to accomplish this?
OrderSearchBar.js
class OrderSearchBar extends Component{
constructor(props) {
super(props);
this.onChangeInput = this.onChangeInput.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
nature: '',
type: '',
searchBy: '',
startDate: '',
endDate: '',
keyword: ''
}
}
onChangeInput(e) {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
const t = {
nature: this.state.nature,
type: this.state.type,
searchBy: this.state.searchBy,
startDate: this.state.startDate,
endDate: this.state.endDate,
keyword: this.state.keyword
}
axios.post('/search', t)..then(res => console.log(res.data));
/*I can do this for single endpoint.but how do I add multiple endpoints
for use in different pages?*/
this.setState({
nature: '',
type: '',
searchBy: '',
startDate: '',
endDate: '',
keyword: ''
});
}
You can differentiate the current location in your orderSearchBar.js
by getting the pathname of window.location object.
onSubmit(e) {
e.preventDefault();
const t = {
nature: this.state.nature,
type: this.state.type,
searchBy: this.state.searchBy,
startDate: this.state.startDate,
endDate: this.state.endDate,
keyword: this.state.keyword
}
const pathName = window && window.location.pathname;
const destination = (pathName === '/purchases') ? '/purchaseDetails' : '/orders'
axios.post(destination, t)..then(res => console.log(res.data));
this.setState({
nature: '',
type: '',
searchBy: '',
startDate: '',
endDate: '',
keyword: ''
});
}
While you could use window property, this might not work if you're using Nuxt.js or other server side rendering, since the window object is not present.
Instead, I suggest you pass a prop down to your component, say:
<component :type="'isPurchaseDetails'">
or for purchases
<component :type="'isPurchases'">

How to do setState for an object inside constructor -> state?

How to do setState for {items.name} an object which is inside constructor -> this.state -> items: { name: '', age:'' }
Inside the constructor instead on doing setState you can assign value to this.state
this.state = {
name: "",
age: ""
}
But there is rarely a use case where in you need to do it this way.
If you need to set the state of bugDetail ,
in constructor you can do this:
constructor(props) {
super(props);
this.state = { bugTitle : '',
bugDescription : '',
bugType : '',
bugDetail : { title : '', description : '', type: '' },
bugDetailArray : [] } }
do the following later: ->
this.setState({bugDetail:{title:"updated",description : 'olderdesc', type:"older"}})
also can do:->
updateTitle(updatedTitle){
let newBugdetail = this.state.bugDetail;
newBugdetail.title = updatedTitle;
this.setState({bugDetail:newBugdetail })
}
else you need to keep the title as an outside key in the state
I believe that your constructor looks like this
constructor(props) {
super(props);
this.state = {
bugTitle : '',
bugDescription : '',
bugType : '',
bugDetail : {
title : '',
description : '',
type: ''
},
bugDetailArray : []
}
}
So in order to change the state using setState in your function
someFunction = (e) => {
let inputName = e.target.name;
let inputValue = e.target.value;
let updatedFormState = Object.assign({}, this.state);
updatedFormState.bugDetail["title"] = inputValue;
this.setState(updatedFormState);
}

Unable to update form field in react via prevState

I have a state variable as:
constructor(props) {
super(props)
this.state = {
fields: {
applicantName: '',
applicantType: '',
applicantAddress: '',
applicantContact: '',
buildingName: '',
buildingAddress: '',
area:'',
}
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
and I have a function :
handleChange(event) {
this.setState((prevState) => {
fields: {
...prevState.fields, //Unexpected token ..
{
event.target.name: event.target.value,
},
}
});
}
How I am not able to see any type of syntax here...but my module build fails and it says syntax error near '...'
you need return Object
handleChange(event) {
// note here => ({
this.setState((prevSate) => ({
fields: {
...prevState.fields,
//and there ..
[event.target.name]: event.target.value
})
});
}
UPDATE
Based on Abdullah suggestion, its better when you use ...prevState for wohle state:
handleChange(event) {
// note here => ({
this.setState((prevSate) => ({
// note change here
...prevState,
fields: {
...prevState.fields,
//and there ..
[event.target.name]: event.target.value
})
});
}
UPDATE 2
based on PraveenRaoChavan comment:
typo fix:
need use event not e
handleChange(event) {
this.setState(prevState => ({
fields: {
...prevState.fields,
{
event.target.name: e.target.value,
},
}
}));
}
You have a typo in there
change
this.setState((prevSate) => { }
to
this.setState((prevState) => { }

React - state won't update

i am building small react app and i have strange situation that state won't update. Here is example:
class App extends Component {
constructor() {
super();
this.state = {
locale: 'de',
countryList: [],
fetchInProgress: true,
serverError: {},
person: {
salutation: '',
firstName: '',
lastName: '',
birthDate: '',
nationality: '',
address: '',
zipCode: '',
city: '',
country: '',
mobileNumber: '',
email: '',
correspondanceLanguage: '',
}
};
}
componentDidMount() {
this.setState({
fetchInProgress: false
}),()=>console.log('State updated', this.state)
}
}
I tried also using other approaches:
componentDidMount() {
const temp = {...this.state};
temp.fetchInProgress = false;
this.setState(temp),()=>console.log('State updated', this.state)
}
componentDidMount() {
const temp = {...this.state};
temp['fetchInProgress'] = false;
this.setState(temp),()=>console.log('State updated', this.state)
}
But never gets state updated. Any help?
You have syntax errors in all of your approaches. Note that setState() has the following format:
setState(updater, callback)
where updater can either be a function or an object and where callback is a function.
Starting with your initial approach:
this.setState({
fetchInProgress: false
}),()=>console.log('State updated', this.state)
should instead be:
this.setState({
fetchInProgress: false
},()=>console.log('State updated', this.state))
The other code is correct until, again, you get to the setState() part:
this.setState(temp),()=>console.log('State updated', this.state)
should instead be:
this.setState(temp,()=>console.log('State updated', this.state))

Resources