Can't get Materialize Picker to work in React - reactjs

I am new to React and can't seem to get my Materialize Picker to work at all.
I have all the Materialize installed and imported.
It displays correctly and opens correctly but when I select a date, I get an error displaying every time and can't figure out why.
TypeError: Cannot read property 'completeBy' of undefined
I have added all my code below for my test page where it's currently sitting.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addToDo } from '../../store/actions/todoActions';
import { Redirect } from 'react-router-dom';
import M from "materialize-css";
//import moment from 'moment';
class AddToDo extends Component {
state = {
title: '',
content: '',
assignTo: '',
completeBy: new Date(),
format: 'ddd d, mmm',
//formatMoment: 'ddd D, MMM'
}
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault();
this.props.addToDo(this.state);
this.props.history.push('/');
}
handleCancel = (e) => {
e.preventDefault();
this.props.history.push('/');
}
canBeSubmitted() {
const { title, content, assignTo } = this.state;
return title.length > 0 && content.length > 0 && assignTo.length > 0;
}
componentDidMount() {
let selects = document.querySelectorAll('select');
let elems = document.querySelectorAll('.datepicker');
M.Datepicker.init(elems, {
defaultDate: new Date(),
format: this.state.format,
container: 'body',
onSelect: function(date) {
this.setState({ completeBy: this.state.completeBy }); // Errors here
},
autoClose: true
});
M.FormSelect.init(selects, {});
}
render() {
const { auth } = this.props;
const isEnabled = this.canBeSubmitted();
if (!auth.uid) {
return <Redirect to='/login' />
}
return (
<div className="container">
<form className="white" onSubmit={ this.handleSubmit }>
<h5 className="grey-text text-darken-3">Add a new todo item</h5>
<div className="input-field">
<input type="text" id='title' onChange={ this.handleChange } autoFocus />
<label htmlFor="title">Todo title <span className="red-text">*</span></label>
</div>
<div className="input-field">
<textarea id="content" className="materialize-textarea" onChange={ this.handleChange }></textarea>
<label htmlFor="content">Todo content <span className="red-text">*</span></label>
</div>
<div className="input-field">
<select id="assignTo" onChange={ this.handleChange }>
<option value="default" disabled selected>Please select</option>
<option value="Kyle">Kyle</option>
<option value="Mike">Mike</option>
<option value="Tony">Tony</option>
</select>
<label htmlFor="assignTo">Assign todo to <span className="red-text">*</span></label>
</div>
<div className="input-field">
<label htmlFor="completeBy">To be completed by</label>
<input
id="completeBy"
type="text"
className="datepicker dateset"
// defaultValue={ moment(this.state.completeBy).format(
// this.state.formatMoment
// )}
/>
</div>
<div className="row">
<div className="col s12 l1">
<button className="btn pink lighten-1 col s12" disabled={!isEnabled}>Add</button>
</div>
<div className="col s12 l1">
<button onClick={this.handleCancel} className="btn yellow darken-2 col s12">Cancel</button>
</div>
</div>
</form>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return {
addToDo: (todo) => dispatch(addToDo(todo))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AddToDo)
Some may recognise the code base as I was following Net Ninja tutorials but adding to it for my learning. I have also had a look at the following stack question and tried their solution as its the same code as mine also but it does not work for me.
I have checked my package.json and I am using "materialize-css": "^1.0.0-rc.2" and I am not using react-materialize.
Screenshots
Initial load
Click in the date field
Set a date, picker closes and get

Most of the time I use arrow functions when I define callbacks. Because it handles the scope of this differently than a function. Try to replace onSelect callback to an arrow function:
M.Datepicker.init(elems, {
defaultDate: new Date(),
format: this.state.format,
container: 'body',
onSelect: (date) => {
this.setState({ completeBy: this.state.completeBy });
},
autoClose: true
});

Related

react hook form get error object after triggering validation

When using trigger() on react hook form I can't read the errors object on first attempt. I think this is because the object populates on a subsequent render.
Here is full working example: https://codesandbox.io/s/crimson-firefly-f8ulg7?file=/src/App.tsx
You can see the first time you click submit it logs an empty object and does not set focus. If you click it again then it will work as intended.
Here is example form code:
import "./styles.css";
import classNames from "classnames";
import { useForm } from "react-hook-form";
export default function App() {
const {
register,
handleSubmit,
trigger,
watch,
formState: { errors }
} = useForm();
const onSubmit = (data: any) => console.log(data);
return (
<div className="App">
<div className="form">
<form onSubmit={handleSubmit(onSubmit)}>
<div className={"row"}>
<div className="label">Name</div>
<div
className={classNames({
input: true,
error: errors?.name !== undefined
})}
>
<input {...register("name", { required: "Name is required" })} />
</div>
</div>
<div className="row">
<div className="label">Company</div>
<div
className={classNames({
input: true,
error: errors?.company !== undefined
})}
>
<input
{...register("company", { required: "Company is required" })}
/>
</div>
</div>
<div className="row">
<div className="label">Tel</div>
<div
className={classNames({
input: true,
error: errors?.tel !== undefined
})}
>
<input
{...register("tel", { required: "Telephone is required" })}
/>
</div>
</div>
<div className="row">
<div className="label">Mobile</div>
<div
className={classNames({
input: true,
error: errors?.mobile !== undefined
})}
>
<input
{...register("mobile", { required: "Mobile is required" })}
/>
</div>
</div>
<div className="row">
<div className="label">Email</div>
<div
className={classNames({
input: true,
error: errors?.email !== undefined
})}
>
<input
{...register("email", { required: "Email is required" })}
/>
</div>
</div>
</form>
</div>
<div className="button">
<a
href="#"
onClick={() => {
trigger().then((res) => {
if (res) {
handleSubmit(onSubmit)();
} else {
let elem = errors[Object.keys(errors)[0]]
?.ref as HTMLInputElement;
elem?.focus();
// setTimeout(() => {
// (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();
// }, 10);
// (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();
console.log(errors);
}
});
}}
>
Submit
</a>
</div>
</div>
);
}
I tried using a timeout but it's still empty on the first attempt.
How do I trigger the forms validation and run code based on the results of the validation?
I want to know the errored fields but also have the ref that is included inside the error object.
After reviewing the comment from the other answer you can access the error object by using the getFieldState in the useForm hook and then calling it in your trigger console.log('error object', getFieldState('name').error). You can also just call console.log('field state', getFieldState('name')) to get more info for that field, including the error object.
I forked your sandbox with the updated code.
const {
register,
handleSubmit,
trigger,
getFieldState,
watch,
formState: {
errors
}
} = useForm();
<a
href = "#"
onClick = {
() => {
trigger().then((res) => {
if (res) {
handleSubmit(onSubmit)();
} else {
let elem = errors[Object.keys(errors)[0]] ?
.ref as HTMLInputElement;
elem ? .focus();
// setTimeout(() => {
// (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();
// }, 10);
// (errors[Object.keys(errors)[0]]?.ref as HTMLInputElement).focus();
console.log("field state", getFieldState("name"));
console.log("error object", getFieldState("name").error);
console.log(errors);
}
});
}
} >
Submit
</a>
Works for react-hook-form version 7+
import "./styles.css";
import classNames from "classnames";
import { useForm } from "react-hook-form";
export default function App() {
const {
register,
handleSubmit,
trigger,
watch,
formState: { errors }
} = useForm();
const onSubmit = (data: any) => {
// send request
};
return (
<div className="App">
<div className="form">
<form onSubmit={handleSubmit(onSubmit)}>
// ...
</form>
</div>
// Not under the form
<button
className="button"
onClick={async () => {
// Check the validation of field
const validationResult = await trigger('name', {shouldFocus: true});
// Show the result of validation
console.log('Field name is valid? ->', validationResult);
console.log('Field name current value', getValues().name);
// Submit or not submit the form
if (validationResult) { handleSubmit(onSubmit)(); }
}}
>
Submit
</button>
</div>
);
}

React Datepicker - Uncaught RangeError: Invalid time value

Building a simple ToDo list app in ReactJS. Below is my Add Task functional component:
import React, { useState } from "react";
import TaskDataService from "../services/task.service";
import DatePicker from 'react-datepicker'
import FadeIn from 'react-fade-in';
import "react-datepicker/dist/react-datepicker.css";
import 'bootstrap/dist/css/bootstrap.min.css';
const AddTask = () => {
const initialTaskState = {
id: null,
title: "",
description: "",
completed: false,
startDate: new Date()
};
const [task, setTask] = useState(initialTaskState);
const [submitted, setSubmitted] = useState(false);
const handleInputChange = event => {
const { name, value } = event.target;
setTask({ ...task, [name]: value });
};
const saveTask = () => {
var data = {
title: task.title,
description: task.description,
startDate: task.startDate
};
TaskDataService.create(data)
.then(response => {
setTask({
id: response.data.id,
title: response.data.title,
description: response.data.description,
completed: response.data.completed,
startDate: response.data.startDate
});
setSubmitted(true);
console.log(response.data);
})
.catch(e => {
console.log(e);
});
};
const newTask = () => {
setTask(initialTaskState);
setSubmitted(false);
};
return (
<FadeIn>
<div className="submit-form">
{submitted ? (
<div>
<h4>Task submitted successfully!</h4>
<button className="btn btn-success" onClick={newTask}>
Add
</button>
</div>
) : (
<div>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="title"
required
value={task.title}
onChange={handleInputChange}
name="title"
/>
</div>
<div className="form-group">
<label htmlFor="description">Description</label>
<input
type="text"
className="form-control"
id="description"
required
value={task.description}
onChange={handleInputChange}
name="description"
/>
</div>
<div className="form-group">
<label htmlFor="startDate">Start Date</label>
<DatePicker
selected={ task.startDate }
onChange={date => handleInputChange({target: {value: date.toISOString().split("T")[0], name: 'startDate'}})}
name="startDate"
dateFormat="yyyy-MM-dd"
/>
</div>
<button onClick={saveTask} className="btn btn-success">
Submit
</button>
</div>
)}
</div>
</FadeIn>
);
}
export default AddTask;
When I try to select a date from the Datepicker calendar, app rendering crashes. There are a few errors but it looks like the main one is "Uncaught RangeError: Invalid time value". However, the task is successfully added to the database and I can view it upon reloading the app. But for whatever case, it crashes upon submit.
In contrast, this is my standalone Task component which also contains code for editing an existing task. In that component, everything works 100%. I can open the Datepicker calendar on the selected task, select a new date, and submit it succesfully with zero problems:
import React, { useState, useEffect } from "react";
import { useParams, useNavigate } from "react-router-dom";
import TaskDataService from "../services/task.service";
import DatePicker from 'react-datepicker';
import FadeIn from 'react-fade-in';
const Task = props => {
const { id } = useParams();
let navigate = useNavigate();
const initialTaskState = {
id: null,
title: "",
description: "",
completed: false,
startDate: new Date(),
};
const [currentTask, setCurrentTask] = useState(initialTaskState);
const [message, setMessage] = useState("");
const getTask = id => {
TaskDataService.get(id)
.then(response => {
setCurrentTask(response.data);
console.log(response.data);
})
.catch(e => {
console.log(e);
});
};
useEffect(() => {
if (id)
getTask(id);
}, [id]);
const handleInputChange = event => {
const { name ,value } = event.target;
setCurrentTask({ ...currentTask, [name]: value });
};
const updateCompleted = status => {
var data = {
id: currentTask.id,
title: currentTask.title,
description: currentTask.description,
completed: currentTask.completed,
startDate: currentTask.startDate
};
TaskDataService.update(currentTask.id, data)
.then(response => {
setCurrentTask({ ...currentTask, completed: status });
console.log(response.data);
})
.catch(e => {
console.log(e);
});
};
const updateTask = () => {
TaskDataService.update(currentTask.id, currentTask)
.then(response => {
console.log(response.data);
setMessage("The task was updated successfully!");
})
.catch(e => {
console.log(e);
});
};
const deleteTask = () => {
TaskDataService.remove(currentTask.id)
.then(response => {
console.log(response.data);
navigate("/tasks");
})
.catch(e => {
console.log(e);
});
};
return (
<FadeIn>
<div>
{currentTask ? (
<div className="edit-form">
<h4>Task</h4>
<form>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="title"
value={currentTask.title}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="description">Description</label>
<input
type="text"
className="form-control"
id="description"
value={currentTask.description}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label>
<strong>Status:</strong>
</label>
{currentTask.completed ? "Completed" : "Pending"}
</div>
<div className="form-group">
<label htmlFor="startDate">Start Date</label>
<DatePicker
onChange={date => handleInputChange({target: {value: date.toISOString().split("T")[0], name: 'startDate'}})}
name="startDate"
dateFormat="yyyy-MM-dd"
value={currentTask.startDate.toString().split("T")[0]}
/>
</div>
</form>
{currentTask.completed ? (
<button
className="badge badge-primary mr-2"
onClick={() => updateCompleted(false)}
>
Mark Pending
</button>
) : (
<button
className="badge badge-primary mr-2"
onClick={() => updateCompleted(true)}
>
Mark Complete
</button>
)}
<button
className="badge badge-danger mr-2"
onClick={deleteTask}
>
Delete
</button>
<button
type="submit"
className="badge badge-success"
onClick={updateTask}
>
Update
</button>
<p>{message}</p>
</div>
) : (
<div>
<br />
<p>Please click on a Task...</p>
</div>
)}
</div>
</FadeIn>
);
}
export default Task;
Done a lot of testing and research but no dice. Any ideas?
Commenter Konrad Linkowski provided the clue to the solution. I removed the line "startDate: response.data.startDate" and now it all works. I do not fully understand, so if anyone wants to explain the answer then please feel free.

ReactJS How to update the state in object which is in the array

Hello I have one problem that I don't know ho to solve.
I have simple formular where the user type som inputs. After that when he clicks on the Button the firstName, lastname and picture will be display under the formular. And when I click on the input it will show the address and date.
But I have problem to do that. In App.js I have a state which initialli si empty array and after click on submit button the user inputs is added to this empty array. In Suggestions.js I map the sugestions array for displaying every suggestion from the user.
In UserInputs.js I have a state where I add into state a 'visible' to false and I want to do, when I clicked on on suggestion in a list it will display the description and date below this particular sugestion.
I want to do it like this. In App.js
const detail = (suggestion) => {
setSuggestions([...suggestions]); //but I don't know how to set state for particular
suggestion in the array.
};
My code:
App.js
import React, { useState } from "react";
import Suggestions from "./components/Suggestions";
import UserInputs from "./components/UserInputs";
function App() {
const [suggestions, setSuggestions] = useState([]);
const addNewSuggestion = (suggestion) => {
setSuggestions([suggestion, ...suggestions]);
};
const detail = (suggestion) => {
setSuggestions([...suggestions]);
};
console.log("suggestions", suggestions);
return (
<div className="app-container">
<UserInputs addNewSuggestion={addNewSuggestion}></UserInputs>
<Suggestions suggestions={suggestions} detail={detail}></Suggestions>
</div>
);
}
export default App;
Suggestions.js
import React from "react";
export default function Suggestions({ suggestions, detail }) {
return (
<div className="suggestion-container">
<h1 className="suggestion-heading">Zoznam Podnetov</h1>
{suggestions.map((suggestion, index) => {
return (
<div
key={suggestion.id}
className="suggestion"
onClick={() => detail(suggestion)}
>
<div className="suggestion-number">{index + 1}</div>
<div className="suggestion-details">
<div className="suggestion-name">
{suggestion.firstName}
{` ${suggestion.lastName}`}
</div>
<div className="suggestion-address">{suggestion.address}</div>
{suggestion.visible ? (
<div className="suggestion-description">
<p>{suggestion.description}</p>
<p>Podnet bol pridaný: {suggestion.date}</p>
</div>
) : null}
</div>
<div className="suggestion-picture">
<img
src={suggestion.picture}
alt="obrázok"
className="suggestion-picture"
></img>
</div>
</div>
);
})}
</div>
);
}
Userinputs.js
import React, { useState } from "react";
export default function UserInputs({ addNewSuggestion }) {
const randomId = Math.floor(Math.random() * 1000000);
const [userInputs, setUserInputs] = useState({
id: randomId,
firstName: "",
lastName: "",
address: "",
description: "",
picture: null,
date: new Date().toLocaleDateString(),
visible: true,
});
const onInputChange = (event) => {
setUserInputs({
...userInputs,
[event.target.name]: event.target.value,
});
};
const fileSelectHandler = (event) => {
setUserInputs({
...userInputs,
picture: URL.createObjectURL(event.target.files[0]),
});
};
const onSubmit = (event) => {
event.preventDefault();
addNewSuggestion(userInputs);
setUserInputs({
id: randomId,
firstName: "",
lastName: "",
address: "",
description: "",
picture: null,
date: new Date().toLocaleDateString(),
visible: true,
});
};
return (
<div>
<form className="form-container">
<div className="row">
<label>Meno</label>
<input
autoFocus
type="text"
name="firstName"
value={userInputs.firstName}
onChange={onInputChange}
></input>
</div>
<div className="row">
<label>Priezvisko</label>
<input
type="text"
name="lastName"
value={userInputs.lastName}
onChange={onInputChange}
></input>
</div>
<div className="row">
<label>Adresa</label>
<input
type="text"
name="address"
value={userInputs.address}
onChange={onInputChange}
></input>
</div>
<div className="row">
<label>Popis</label>
<input
type="text"
name="description"
value={userInputs.description}
onChange={onInputChange}
></input>
</div>
<div className="row">
<input type="file" onChange={fileSelectHandler}></input>
</div>
<button onClick={onSubmit} className="button">
Odoslať
</button>
</form>
</div>
);
}
Thank you very much for your help.
you can update the suggestion, where the id matches input suggestion and only update it. Please find the code below:
const detail = (suggestion) => {
let tempSuggestions = suggestions.map( (item) => {
if(item.id === suggestion.id) return suggestion
return item
})
setSuggestions([...tempSuggestions]);
}

TypeError: Cannot read property 'name' of undefined - react

I have a form with a 'title' and a 'content'. The content is in the ReactQuill component which enables you to have rich text. Before adding that component, my 'onChange' was working fine for both 'inputs'. Now that the components are different it no longer works.
I get the error below:
this is the code in AddArticle.js which is where the form is:
import React, { Component } from "react";
import firebase from "../Firebase";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
import renderHTML from "react-render-html";
class AddArticle extends Component {
constructor() {
super();
this.ref = firebase.firestore().collection("articles");
this.state = {
title: "",
content: "",
};
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = (e) => {
e.preventDefault();
const { title, content } = this.state;
this.ref
.add({
title,
content,
})
.then((docRef) => {
this.setState({
title: "",
content: "",
});
this.props.history.push("/");
})
.catch((error) => {
console.error("Error adding document: ", error);
});
};
render() {
return (
<div className="container">
<br></br>
<br></br>
<br></br>
<div className="panel panel-default">
<div className="panel-heading">
<h3 className="panel-title text-center">Create a new article</h3>
</div>
<br></br>
<br></br>
<div className="panel-body">
<form onSubmit={this.onSubmit}>
<div className="form-group input-group-lg">
<label for="title">Title:</label>
<input
type="text"
className="form-control"
name="title"
value={this.state.title}
onChange={this.onChange}
placeholder="Title"
/>
</div>
<div className="form-group">
<label for="content">Content:</label>
<ReactQuill
theme="snow"
name="content"
value={this.state.content}
onChange={this.onChange}
placeholder="Content"
/>
</div>
<button type="submit" className="btn btn-success">
Submit
</button>
</form>
</div>
</div>
</div>
);
}
}
export default AddArticle;
The onChange for the title input receives an event containing name and value.
On the other hand the onChange for the Quill component receives the actual content.
All in all you should use:
onTitleChange = (e) => {
this.setState({ title: e.target.value });
};
onContentChange = (content) => {
this.setState({ content: content });
};
And pass these handlers approprietly to your title input and quill component.

How do I set the value of an input after doing an Axios get request?

I have a component that represents a form for entering book data, e.g. title/author/etc.
If an ID is present, the component will make an API call to the API server, and get the book data.
What I'm trying to accomplish basically, is getting the record from the API server, and then setting the form fields to those values, so that the form is populated with data for the user to edit.
I have a method called loadBook which makes an API call to get the book data. The method works, it gets the record, it sets the state, but the form inputs do not seem to pick up that the state has changed.
What do I need to do to get the form populated with the record that was just fetched?
import React from "react";
import Axios from "axios";
import {
Redirect
} from "react-router-dom";
import FormBase from "../FormBase";
export default class BookForm extends FormBase {
constructor(props) {
super(props);
this.state = {
formFields: {
title: '',
author_id: null,
cover_image: null
},
authors: [],
};
}
componentDidMount() {
this.loadAuthors();
if (this.props.id) {
this.loadBook()
}
}
loadBook = () => {
Axios.get(`${process.env.REACT_APP_API_URL}/books/${this.props.id}`).then(response => {
this.setState(prevState => {
let formFields = Object.assign({}, prevState.formFields)
formFields['title'] = response.data['title']
formFields['author_id'] = response.data['author_id']
return {formFields}
})
})
}
loadAuthors = () => {
Axios.get(`${process.env.REACT_APP_API_URL}/authors`).then(response => {
this.setState({authors: response.data})
})
}
render() {
let authors = this.state.authors.map(author => {
return <option key={author.id} value={author.id}>{author.last_name}, {author.first_name}</option>
})
return (
<form onSubmit={(e) => {e.preventDefault(); this.props.handleSubmit(e, this.state.formFields, true)}}>
{this.state.redirect ? <Redirect to="/admin/books" /> : null}
<div className="form-group">
<label htmlFor="title">Title</label>
<input name="title" value={this.state.title} onChange={this.handleFieldChange} type="text" className="form-control" />
</div>
<div className="form-group">
<label htmlFor="author">Author</label>
<select name="author_id" onChange={this.handleFieldChange} className="custom-select" size="5">
{authors}
</select>
</div>
<div className="custom-file form-group">
<input name="cover_image" type="file" onChange={this.handleFieldChange} className="custom-file-input" id="customFile" />
<label className="custom-file-label" htmlFor="customFile">Cover Image</label>
</div>
<button style={{marginTop: '1rem'}} type="submit" className="btn btn-primary">Submit</button>
</form>
)
}
}
Try setting your state simply like so:
this.setState({formFields:
{
...this.state.formFields,
title: response.data['title'],
author_id: response.data['author_id']
}
})
I essentially followed this guide on uncontrolled components.
I added attributes for each form field using React.createRef(), and then on the form inputs you link the ref object like ref={this.author_id}. Then, you can do this.author_id.current.value = response.data.author_id and the input's value will then be set. This won't trigger onChange though, so you'll need to update the state too.
import React from "react";
import Axios from "axios";
import {
Redirect
} from "react-router-dom";
import FormBase from "../FormBase";
export default class BookForm extends FormBase {
constructor(props) {
super(props);
this.state = {
formFields: {
title: '',
author_id: null,
cover_image: null
},
authors: [],
};
this.title = React.createRef();
this.author_id = React.createRef();
}
componentDidMount() {
this.loadAuthors();
if (this.props.id) {
this.loadBook()
}
}
loadBook = () => {
Axios.get(`${process.env.REACT_APP_API_URL}/books/${this.props.id}`).then(response => {
console.log(this.author_id)
this.author_id.current.value = response.data.author_id
this.title.current.value = response.data.title
this.setState(prevState => {
let formFields = Object.assign({}, prevState.formFields)
formFields['title'] = response.data['title']
formFields['author_id'] = response.data['author_id']
return {formFields}
})
})
}
loadAuthors = () => {
Axios.get(`${process.env.REACT_APP_API_URL}/authors`).then(response => {
this.setState({authors: response.data})
})
}
render() {
let authors = this.state.authors.map(author => {
return <option key={author.id} value={author.id}>{author.last_name}, {author.first_name}</option>
})
return (
<form onSubmit={(e) => {e.preventDefault(); this.props.handleSubmit(e, this.state.formFields, true)}}>
{this.state.redirect ? <Redirect to="/admin/books" /> : null}
<div className="form-group">
<label htmlFor="title">Title</label>
<input name="title" ref={this.title} value={this.state.title} onChange={this.handleFieldChange} type="text" className="form-control" />
</div>
<div className="form-group">
<label htmlFor="author">Author</label>
<select name="author_id" ref={this.author_id} onChange={this.handleFieldChange} className="custom-select" size="5">
{authors}
</select>
</div>
<div className="custom-file form-group">
<input name="cover_image" type="file" onChange={this.handleFieldChange} className="custom-file-input" id="customFile" />

Resources