Can't send files using Redux Form - reactjs

I'm creating a webpage for me and I'm working with Redux/Redux Form. My backend is working fine, but I can't figure out how to work on my front-end. I'm not using any library to fetch the image in my front, I just copy and pasted a FieldFileInput and it's working fine.
Here is my PostForm.tsx:
renderInput = ({input, label, meta}: {input: any, label: any, meta: any}) => {
const className = `field ${meta.error && meta.touched} ? 'error' : ''`;
return (
<div className={className}>
<label>{label}</label>
<div className="input-group input-group-lg">
<input className="form-control"{...input} autoComplete="off"/>
</div>
{this.renderError(meta)}
</div>
)
};
onSubmit = (formValues: any) => {
//#ts-ignore
this.props.onSubmit(formValues)
};
render() {
return (
<form
onSubmit={ this.props.handleSubmit(this.onSubmit)}
className="ui form error"
>
<div className="create-post-field-two">
<Field
name="title"
component={this.renderInput}
label="Enter Title"
/>
</div>
<div className="create-post-field-two">
<Field
name="body"
component={this.renderInput}
label="Enter Description"
/>
</div>
<div className="create-post-field-two">
<Field
name="imageUrl"
component={FieldFileInput}
label="Enter Image"
/>
</div>
<div className="postButton">
<button className="btn btn-outline-secondary">Submit</button>
</div>
</form>
)
}
}
In this page I'm certain that everything works correctly, because I receive all data in my Action.
Here is my Redux Action
export const createPost = ( formValues: any) => async(dispatch: any, getState: any) => {
const { userId } = getState().auth;
let token = userId
const headers = {
// 'Content-Type': 'multipart/form-data',
authorization: `Bearer ${token}`,
};
let formData = new FormData();
formData.append('imageUrl', formValues.imageUrl);
try {
const response = await AlleSys.post('/posts', {...formValues, image: formData}, {headers})
dispatch({type: CREATE_POST, payload: response.data})
history.push('/')
}catch (err) {
console.log("ERROR: Couldn't post for identified user");
}
};
If I uncomment the Content-Type I receive the error Error: Multipart: Boundary not found
in my Back-End.
Here Is a screenshot of my request using insomnia.
I'm stuck on this for days and I can't figure out how to achieve the file upload in the front-end. Please don't mind the typings, I'll correct later.

I used bodyFormData.append to my form fields in the Redux Action and worked like a charm.
export const createPost = ( formValues: any) => async(dispatch: any, getState: any) => {
const { userId } = getState().auth;
let token = userId
const headers = {
authorization: `Bearer ${token}`,
Accept: 'application/json',
};
const { title, body, image } = formValues;
const bodyFormData = new FormData();
bodyFormData.append('title', title);
bodyFormData.append('body', body);
bodyFormData.append('image', image);
try {
const response = await AlleSys.post('/posts', bodyFormData, {headers})
console.log(response)
dispatch({type: CREATE_POST, payload: response.data})
history.push('/')

Related

Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob' ReactJS

Guys why does it show me this error when I try to upload a PDF file "Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'":
function Test() {
const [file, setFile] = useState()
const SubmitFile = (e) =>{
e.preventDefault()
const formdata = new FormData()
try {
formdata.append(
'file',
file,
file.name,
)
axios.post("http://localhost:3001/upload", formdata,{
headers:{
"Content-type": "multipart/form-data"
},
})
} catch (err) {
console.log(err.message)
}
}
return (
<div>
<h1>File upload</h1>
<form onSubmit={SubmitFile}>
<input onChange={(e)=>{setFile(e.target.files)}} accept="application/pdf" type=
{"file"} id='file' />
<input type={"submit"} value="submit" />
</form>
</div>
)
}
export default Test
I just had to change into this:
let formdata = new FormData()
try {
formdata.append(
'file',
file[0],
file.name,
)

Struggling with PUT request

I'm on React for 2 months, and still struggling with CRUD operations such as EDIT.
I've been trying couple different ways, but every time I send nothing to my API.
I do not manage to grab the information correctly in order to push it to the server.
The route is working with Postman, there are no issues there, it's only React and me ^^.
I would be grateful if someone could read my code and tell me where the problem might come from, thanks !
1st try
const usernamelEl = React.useRef(null)
const timezoneEl = React.useRef(null)
const handleEditProfile = async () => {
const creds = {
user: {
username: usernameEl.current.value,
timezone: timezoneEl.current.value
}
};
const config = {
method: 'PUT',
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Authorization": `Bearer ${Cookies.get('token')}`
},
body: JSON.stringify(creds)
};
const res = await fetch(`${process.env.REACT_APP_API_URL}api/users/${id}`, config);
const user = await res.json();
console.log(user)
}
return (
<form onSubmit={handleEditProfile} className="form">
<div className="input-group">
<label htmlFor="username">username</label>
<input type="text" id="username" ref={usernameEl}/>
</div>
<div className="input-group">
<label htmlFor="timezone">timezone</label>
<input type="text" id="timezone" ref={timezoneEl}/>
</div>
<div className="input-group">
<SubmitButtonComponent type="submit">
Submit
</SubmitButtonComponent>
</div>
</form>
)
2nd try
const [usernameEl, setUsernameEl] = useState('')
const [timezoneEl, setTimezoneEl] = useState('')
const handleChangeUsername = e => {
setUsernameEl(e.target.value)
}
const handleChangeTimezone= e => {
setTimezoneEl(e.target.value)
}
const handleEditProfile = async (e) => {
const creds = {
user: {
username: usernameEl,
timezone: timezoneEl
}
};
const config = {
method: 'PUT',
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Authorization": `Bearer ${Cookies.get('token')}`
},
body: JSON.stringify(creds)
};
const res = await fetch(`${process.env.REACT_APP_API_URL}api/users/${id}`, config);
const data = await res.json();
console.log(data)
try {
setUsernameEl('')
setTimezoneEl('')
}
catch(err) {
console.log(err)
}
}
return (
<form className="form" onSubmit={handleEditProfile}>
<div className="input-group">
<label htmlFor="username">username</label>
<input type="text" id="username" onChange={handleChangeUsername}/>
</div>
<div className="input-group">
<label htmlFor="timezone">timezone</label>
<input type="text" id="timezone" onChange={handleChangeTimezone}/>
</div>
<SubmitButtonComponent type="submit">
Submit
</SubmitButtonComponent>
</form>
if I ever try to pass a value
const handleEditProfile = async (e) => {
e.preventDefault();
[..]
onSubmit={(e)=>handleEditProfile(e.target.value)}>
or
onSubmit={handleEditProfile(e)>
then I get this error

Image upload in mern stack using multer not working

I'm trying to upload image in MongoDB using multer and react but I'm unable to post it. I have three inputs in by form i.e title, content and image. If I try to post title and content only it is successfully being posted. I have also added "proxy": "http://localhost:8000", in frontend package.json file
Here is my form
function PostCreate() {
const [title, setTile] = useState("");
const [content, setContent] = useState("");
const [image, setImage] = useState({});
const dispatch = useDispatch();
const post = useSelector((state) => state.postReducer);
const fileOnChange = (e) => {
setImage(e.target.files[0]);
};
const submitPost = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("image", image);
dispatch(createPost(title, content, image));
};
return (
<div className="postCreate">
<h3 className="postCreate__heading">Create New Post</h3>
<div className="formBody">
<form onSubmit={submitPost}>
<div className="formInputs">
<label className="label">Title</label>
<input
className="titleInput"
type="text"
value={title}
onChange={(e) => setTile(e.target.value)}
placeholder="Enter the Title of the Post"
/>
</div>
<div className="formInputs">
<input type="file" onChange={fileOnChange} />
</div>
<div className="formInputs">
<label className="label">Content</label>
<textarea
className="titleInput"
type="text"
style={{
width: "1500px",
height: "500px",
color: "black",
outline: "none",
border: "none",
borderRadius: "6px",
}}
value={content}
onChange={(e) => setContent(e.target.value)}
/>
</div>
<div className="button">
<Button type="submit" variant="contained" color="primary">
Post
</Button>
</div>
{/* <button type="submit">Post</button> */}
</form>
Here is my action
export const createPost = (title, content, image) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.post(
"/api/newpost",
{ title, content },
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};
Here is my postController
const createPost = async (req, res) => {
const { title, content, writer, comment, image } = req.body;
const fileType = req.file.mimetype.split("/")[1];
const newFileName = req.file.filename + "." + fileType;
fs.rename(
`uploads/images/${req.file.filename}`,
`uploads/images/${newFileName}`,
(req, res) => {
console.log("Renamed");
}
);
// const imageUrl = req.file.filename;
const newPost = await Post.create({
title,
content,
writer,
comment,
image,
// imageUrl,
});
if (newPost) {
res.send("Post created");
console.log("Post created");
} else {
res.status(201).send("Post not created");
console.log("Post not created");
}
};
Here is my routes
router.post("/newpost", upload.single("image"), createPost);
You're creating a form, which is a good start, but not sending it with axios.
To send a file from frontend to backend, you need to construct a form using FormData API and append the file to it. You can also append additional data to it.
Here is how I would change your code to work. In your form file:
const formData = new FormData();
formData.append('image', image);
formData.append('title', title);
formData.append('content', content);
dispatch(createPost(formData));
Then change your action to:
export const createPost = (formData) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "multipart/form-data" } };
const { data } = await axios.post(
"/api/newpost",
formData,
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};

Rect Post request

I am creating project in React /Django Rest Framework and I want to send Post request. My problem is that I am always sending string and I should send list of int.
My component look like this
const NewLecture = (props) => {
const[ lecture, setLecture] = useState({
title:'',
programs: [],
})
const dispatch = useDispatch()
const history = useHistory()
// console.log('this is history:', history)
const program_id = props.match.params.id;
//event handlers
const newLectureHandler = (event) => {
const{name, value}= event.target
setLecture({
...lecture,
[name]:value
})
};
useEffect(() => {
console.log('mounting in NewLecture');
dispatch(LecturesActions())
dispatch(GetPrograms())
}, [])
const handleSubmit = e =>{
e.preventDefault()
props.close()
dispatch(sendLecture(lecture, program_id, history))
}
const stringtoArray = (arg)=> {
console.log('this is arg', [arg]);
return [arg]
}
return (
<NewGradeStyled>
<div className="new-grade-style">
<h1>Create New Lecture</h1>
<form >
<div className="form-grade">
<label htmlFor="title">Lecture Name</label>
<input type="text" name="title" onChange={newLectureHandler}/>
</div>
<div className="form-grade">
<label htmlFor="programs">Program</label>
{/* <input type="number" name="programs" onChange={newLectureHandler}/> */}
<select name="programs" onChange={newLectureHandler}>
<option > </option>
{props.data ? <option value={props.data.id}>{props.data.name}</option> : ''}
</select>
</div>
<div className="btn-group">
<button className="save" onClick={handleSubmit}>Save</button>
<button onClick={props.close}>Cancle</button>
</div>
</form>
</div>
</NewGradeStyled>
)
}
export default withRouter(NewLecture)
and this is my action
export const sendLecture = (lecture) => (dispatch, getState) => {
const{title, programs} = lecture
const token = getState().token
const config = {
body: JSON.stringify(lecture),
method: "POST",
headers: new Headers({
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}),
body: JSON.stringify({title, programs})
};
fetch(`${baseUrl}/backend/api/lectures/new/`, config)
.then((res) => res.json())
.then((data)=>{
console.log('Post lecture action', data)
dispatch({type: 'GET_LECTURE_DATA', payload: data})
});
}
I expect to get this from JSON
{
"title":"some string"
"programs":[1]
}
reducer
const initialState = {
lecture_data:[],
}
export const authReducer = (state = initialState, action) => {
switch (action.type) {
case "GET_LECTURE_DATA": {
const lecture_data = action.payload;
return { ...state, lecture_data };
}
default:
return state;
}
}
If I send it as input type= "number" result is always the same I get error "Expected a list of items but got type "str"."
I donĀ“t kow how I should change it. Do you have any Ideas?
In this part:
const config = {
body: JSON.stringify(lecture),
method: "POST",
headers: new Headers({
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}),
body: JSON.stringify({ title, programs })
};
you set the body property twice. Is that intentional?
You write the api expects a list. Did you mean to pass this body: JSON.stringify( [title, programs ]) Although that would send an array of objects of which the first item is title, and the second is programs. Can you clarify what the API expects? And what the structure of title and programs looks like?

how to fetch and display API content Onsubmit

I am developing a weather forecast app using Reactjs but i'm having a hard time Fetching/displaying API data
I know this question might have a duplicate but i have looked up all related problems/solutions on this platform and elsewhere but none solved my problem
//const API;
class WeatherApp extends React.Component{
constructor(props){
super(props);
this.state = {
location: "",
reports:[]
}
}
//functions should be written outside the constructor method
onSubmit = event => {
//prevents default loading of the page when this function "onSubmit"
//is called
event.preventDefault();
//saving the value of the textbox to a variable/const
if(this.searchbox.value !== ""){
const searchResult = this.searchbox.value;
//update the state object
this.setState({
location: searchResult + " weather report"
});
}else{
alert("please ensure that field is not empty!");
return;
}
};
componentDidMount(){
if(this.searchbox.value !== ""){
fetch(`api.openweathermap.org/data/2.5/forecast?q=london,uk ${/*this.searchbox.value +*/ KEY}`,{
method: "GET",
dataType: "JSON",
headers: {
"Content-Type": "application/json; charset=utf-8",
}
})
.then(response => { response.json() })
.then(data => {
console.log(data);
this.setState({ reports: data.list})
});
}
}
render(){
return(
<div className="weather-app">
<WeatherAppHeader />
<div className="weather-body">
<div className="entry-pane">
<form onSubmit ={this.onSubmit} >
<input
type="text"
id="search-box"
placeholder="Location e.g Abuja, NG"
size="40"
ref={input => this.searchbox = input} />
<button type="submit" id="search-btn">search</button>
</form>
</div>
<SearchedLocation location={this.state.location} />
<WeatherReport reports={this.state.reports} />
</div>
</div>
);
}
}
const WeatherAppHeader = () => (
<nav> WEATHER FORECAST </nav>
);
const SearchedLocation = ({location}) => (
<div className="searched-loc">{location}</div>
);
SearchedLocation.propTypes = {
location: PropTypes.string
}
///Declaring state within the WeatherReport component
const WeatherReport = ({reports}) => (
<div className="weather-report" >
<ul className="report-list">
{reports.map(report => (
<li key={report.id} className="daily-report">
<span className="daily-report-day">{report.day}</span><br/>
<span className="daily-report-icon">{report.icon}</span><br/>
<span className="daily-report-temp">{report.main.temp}</span>
</li>
))}
</ul>
</div>
);
WeatherReport.propTypes = {
report: PropTypes.array
}
ReactDOM.render(<WeatherApp />, document.getElementById('root'));
i want to display all data from the API on the browser console when the form is submitted but to no avail...and theres no error message. pls can anyone help?
After your fetch call, you are not correctly returning the response when you do .then(response => { response.json() }). Just remove the curly-braces, that way you do an implicit return. Otherwise, if you use curly-braces you must explicitly write .then(response => { return response.json() })
Working code:
componentDidMount(){
if(this.searchbox.value !== ""){
fetch(`api.openweathermap.org/data/2.5/forecast?q=london,uk ${/*this.searchbox.value +*/ KEY}`,{
method: "GET",
dataType: "JSON",
headers: {
"Content-Type": "application/json; charset=utf-8",
}
})
.then(response => response.json())
.then(data => {
console.log(data);
this.setState({ reports: data.list})
});
}
}

Resources