After getting member data, member state will be like this.
{
_id: '61d34027ca50827501279eb0',
index: 1,
email: 'bcr90348#zwoho.com',
name: '1',
active: true
}
How to change the values of the above object by changing the text box values?
Ex: Changing the name. Changing email.
import React, { useEffect, useState } from 'react'
import {
CButton,
CCard,
CCardBody,
CCardHeader,
CCol,
CForm,
CFormInput,
CFormLabel,
CRow,
} from '#coreui/react'
import PropTypes from 'prop-types'
const Edit = (props) => {
const id = props.match.params.id
const [member, setMember] = useState({})
const handleLoadMember = async () => {
try {
const _data = await fetch(`http://localhost:4000/api/v1/member/${id}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + localStorage.getItem('token'),
},
})
if (_data.status === 200) {
const data = await _data.json()
setMember(data.member)
} else if (_data.status === 404) {
} else {
throw new Error()
}
} catch (err) {
console.error(err)
}
}
useEffect(() => {
handleLoadMember()
}, [])
return (
<CRow>
<CCol xs={12}>
<CCard className="mb-4 w-75">
<CCardHeader>
<strong>Add New Member</strong>
</CCardHeader>
<CCardBody>
<p className="text-medium-emphasis small">
Click on save button after editing member details.
</p>
<CForm>
<div className="d-inline-flex w-100">
<div className="mb-3 me-1 w-50">
<CFormLabel>Email:</CFormLabel>
<CFormInput
type="email"
placeholder="name#example.com"
value={member.email}
onChange={(e) => console.log(e.target.value)}
/>
</div>
<div className="mb-3 w-50">
<CFormLabel>Name:</CFormLabel>
<CFormInput type="text" placeholder="Perera's Home" value={member.name} />
</div>
</div>
<div className="mb-3">
<CButton color="primary">Submit</CButton>
</div>
</CForm>
</CCardBody>
</CCard>
</CCol>
</CRow>
)
}
Edit.propTypes = {
match: PropTypes.any,
}
export default Edit
Assuming that member already has a value (like you described in your question), you can alter one or multiple properties of it by doing something like this with the spread operator:
setMember(member => ({...member, name: "My New Name", email: "NewEmail"}))
See the Hooks API and useState documentation for more information.
You can define an onChangeHandler like below. And add define name prop to each field.
const onChangeHandler = (e) => {
const { name, value } = e.target;
setMember((prevState) => ({ ...prevState, [name]: value }));
};
<CFormInput
type="email"
placeholder="name#example.com"
name="email"
onChange={onChangeHandler}
value={member.email}
/>
<CFormInput
type="text"
placeholder="Perera's Home"
name="name"
onChange={onChangeHandler}
value={member.name}
/>
Code sandbox
Related
I have a friend form that has a button to add friend via ajax call (addNewFriendClick). Once added it should output the id and then using that id the same button (onClickUpdate) should allow to update by grabbing that id.
After adding and clicking a second time to update the friend I get the error below in my console.
The website below should have the /id as the url ending endpoint but i am getting
"[object%20Object]"
PUT https://api.remotebootcamp.dev/api/friends/[object%20Object] 404 (Not Found)
Below is my Routes
<Route path="/friends/*" element={<AddFriend></AddFriend>}>
<Route path=":personId" element={<AddFriend />}></Route>
<Route path="new" element={<AddFriend />}></Route>
</Route>
import React, { useState, useEffect } from "react";
import * as friendService from "../../services/friendService";
import toastr from "toastr";
import { useParams, useNavigate, useLocation } from "react-router-dom";
function AddFriend() {
const [userFormData, setUserFormData] = useState({
title: "",
bio: "",
summary: "",
headline: "",
slug: "",
statusId: "",
primaryImage: "",
});
// useEffect to grab url
const navigate = useNavigate();
const { state } = useLocation();
const friendId = useParams();
const [peepId, setPeepId] = useState(friendId);
console.log({ userFormData, peepId, state }, "param and navigate");
useEffect(() => {
console.log("useEffect firing");
setPeepId(friendId);
if (state) {
setUserFormData((prevState) => {
console.log(state);
return { ...prevState, ...state.payload };
});
}
}, [friendId, state]);
const onFormFieldChange = (event) => {
const target = event.target;
const value = target.value;
console.log("VALUE ->", value);
const name = target.name;
console.log("NAME ->", name);
setUserFormData((prevState) => {
console.log("updater onChange");
const updatedFormData = {
...prevState,
};
updatedFormData[name] = value;
return updatedFormData;
});
};
useEffect(() => {
console.log("useEffect firing");
setPeepId(friendId);
if (state) {
setUserFormData((prevState) => {
console.log(state);
return { ...prevState, ...state.payload };
});
}
}, [friendId, state]);
const addNewFriendClick = (event) => {
event.preventDefault();
console.log(userFormData, "inside addNewFriendClick")
console.log("on Click", { syntheticEvent: event });
friendService.addFriend(userFormData).then(onSuccessAdd).catch(onErrAdd);
};
const onSuccessAdd = (response) => {
console.log(response, "onSuccessAdd response");
// console.log(response.data.item, "onSuccessAdd response.data.item");
setNewFriendInformation(response);
console.log(response,"onSuccessAdd after setNewFriend" )
friendService.getFriendById(response).then(onSuccessGet).catch(onErrorGet);
toastr.success("Congratulations! You have successfully added a friend!");
};
const onErrAdd = (err) => {
console.log("ping err", err);
// swal("Error Registering");
toastr.error(
"Error adding a new friend. Please check if all fields are correct"
);
};
const onClickUpdate = (event) => {
console.log(userFormData, "userFormData inside click Edit");
event.preventDefault();
friendService
.updateFriend(userFormData)
.then(onSuccessUpdate)
.catch(onErrorUpdate);
};
const onSuccessUpdate = (response) => {
console.log(response);
toastr.success("Congratulations! You have successfully updated a friend!");
navigate("/friends");
};
const onErrorUpdate = (error) => {
console.log(error, "inside error update");
toastr.error(
"Error updating friend. Please check all fields are correct and that user being updated is valid"
);
};
const setNewFriendInformation = (id) => {
setUserFormData((prevState) => {
let newState = { ...prevState };
newState.id = id;
return newState;
});
};
const onSuccessGet = (response) => {
console.log(response);
navigate();
};
const onErrorGet = (error) => {
console.log(error);
console.log("inside getById error form");
};
// const updateFriend()
return (
<React.Fragment>
<h1 className="container">Add New</h1>
<hr />
<main role="main">
<div className="container col-6 mt-5 fs-2">
<div className="row">
<div className="col-md-5">
<form>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Title
</label>
<input
type="text"
className="form-control form-control-lg"
id="title"
name="title"
placeholder="Please The Enter Title"
onChange={onFormFieldChange}
value={userFormData.title}
/>
</div>
<div className="mb-3">
<label htmlFor="bio" className="form-label">
Bio
</label>
<input
type="text"
className="form-control form-control-lg"
id="bio"
name="bio"
placeholder="Please Enter The Bio"
value={userFormData.bio}
onChange={onFormFieldChange}
/>
</div>
<div className="mb-3">
<label htmlFor="summary" className="form-label">
Summary
</label>
<input
type="text"
className="form-control form-control-lg"
id="summary"
name="summary"
placeholder="Please Enter The Summary"
onChange={onFormFieldChange}
value={userFormData.summary}
/>
</div>
<div className="mb-3">
<label htmlFor="headline" className="form-label">
Headline
</label>
<input
type="text"
className="form-control form-control-lg"
id="headline"
name="headline"
placeholder="Please Enter The Headline"
onChange={onFormFieldChange}
value={userFormData.headline}
/>
</div>
<div className="mb-3">
<label htmlFor="slug" className="form-label">
Slug
</label>
<input
type="text"
className="form-control form-control-lg"
id="slug"
name="slug"
placeholder="Please The Slug"
onChange={onFormFieldChange}
value={userFormData.slug}
/>
</div>
<div className="mb-3">
<label htmlFor="statusId" className="form-label">
Status Id
</label>
<select
type="select"
className="form-control"
id="statusId"
name="statusId"
placeholder="Please Enter Status ID"
onChange={onFormFieldChange}
value={userFormData.statusId}
>
<option>Default</option>
<option value="Active">Active</option>
<option value="NotSet">NotSet</option>
<option value="Deleted">Deleted</option>
<option value="Flagged">Flagged</option>
</select>
</div>
<div className="mb-3">
<label htmlFor="primaryImage" className="form-label">
Primary Image Url
</label>
<input
type="text"
className="form-control form-control-lg"
id="primaryImage"
name="primaryImage"
placeholder="Please Enter The Primary Image"
onChange={onFormFieldChange}
value={userFormData.primaryImage}
/>
</div>
{userFormData.id ? (
<button
onClick={onClickUpdate}
type="sumbit"
className="btn btn-primary"
>
Update Friend
</button>
) : (
<button
onClick={addNewFriendClick}
type="sumbit"
className="btn btn-primary"
>
Add Friend
</button>
)}
</form>
</div>
</div>
</div>
<div className="col-md-5">
<h5>Output</h5>
<pre>
<code>{JSON.stringify(userFormData, undefined, 2)}</code>
</pre>
</div>
</main>
</React.Fragment>
);
}
export default AddFriend;
import axios from "axios";
import * as helper from "./serviceHelper";
let getFriend = () => {
const config = {
method: "GET",
url: "https://api.remotebootcamp.dev/api/friends?pageIndex=0&pageSize=10",
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config).then(helper.onGlobalSuccess);
//we use data as the param for success handler
};
let addFriend = (payload) => {
const config = {
method: "POST",
url: "https://api.remotebootcamp.dev/api/friends",
data: payload,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config).then(response => {
console.log(response, "inside service addfriend return")
return response.data.item;
});
}
let updateFriend = (id, payload) => {
console.log(id, payload, "from updateFriendservice");
const config = {
method: "PUT",
data: (id, payload),
url: `https://api.remotebootcamp.dev/api/friends/${id}`,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config);
};
let deleteFriend = (id) => {
console.log(id);
const config = {
method: "DELETE",
// data: id,
url: `https://api.remotebootcamp.dev/api/friends/${id}`,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
};
return axios(config);
};
let getFriendById = (id, payload) =>{
console.log(id, payload, "inside getFriend friedService")
const config = {
method: "PUT",
data: (id, payload),
url: `https://api.remotebootcamp.dev/api/friends/${id}`,
withCredentials: true,
crossdomain: true,
headers: { "Content-Type": "application/json" },
}
return axios(config);
}
export { getFriend, addFriend, deleteFriend, updateFriend, getFriendById };
Maybe you should get friendId as following
const { personId: friendId } = useParams();
Also you need to send two prams to friendService.updateFriend() but sent only one param.
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
const RestaurantUpdate = () => {
const [state, setState] = useState({ name: '', email: '', address: '', rating: '' })
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [address, setAddress] = useState("");
const [rating, setRating] = useState("");
const { id } = useParams();
useEffect(() => {
fetch('http://localhost:3000/restaurant/' + id).then((response) => {
response.json().then((result) => {
console.warn(result.name);
setName(result.name);
setEmail(result.email);
setAddress(result.address);
setRating(result.rating);
})
})
}, []);
function update() {
fetch("http://localhost:3000/restaurant/" + id,
{
method: "PUT",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(state)
}).then((result) => {
result.json().then((resp) => {
alert("Restaurant has been updated");
})
})
}
return (
<div>
<h1>Update</h1>
<div>
<input onChange={(event) => setName(event.target.value)}
placeholder="Restaurant Name" value={name} /> <br /><br />
<input onChange={(event) => setEmail(event.target.value)}
placeholder="Restaurant Email" value={email} /> <br /><br />
<input onChange={(event) => setRating(event.target.value)}
placeholder="Restaurant Rating" value={rating} /> <br /><br />
<input onChange={(event) => setAddress(event.target.value)}
placeholder="Restaurant Address" value={address} /> <br /><br />
<button onClick={() => { update() }}>Update Restaurant</button>
</div>
</div>
);
};
export default RestaurantUpdate;
Want my API to get updated. But it is not working. Attributes of that particular id is getting blank. How to update all the data of that particular id in functional components?
Maybe I have some syntax error or is there any another alternative method?
You're updating the individual pieces of state (name, email, address, rating), but sending the big piece of state (state) with your API call. This piece of state is never updated in your component. It will always send your defualt values, which are empty strings for every property.
You could pass the individual pieces of state to the API call:
function update() {
fetch("http://localhost:3000/restaurant/" + id,
{
method: "PUT",
headers: {
'Content-Type': 'application/json'
},
// use object property shorthand to avoid
// syntax like { name: name, email: email ... }
body: { name, email, address, rating }
}).then((result) => {
result.json().then((resp) => {
alert("Restaurant has been updated");
})
})
}
I have a Register.js component that send a request to an express.js backend and then is validated by express-validator and returns an object that looks like this:
data: {
success: Boolean,
errors: array()
}
Register.js
import React, {useState} from "react";
import { Link } from "react-router-dom";
const RegisterForm = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [errors, setErrors] = useState([]);
const [token, setToken] = useState("");
const handleFormSubmit = (e) => {
e.preventDefault();
const formFields = {
name: username,
password: password
}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formFields)
};
fetch('http://localhost:5000/add_user', requestOptions)
.then(response => response.json())
.then(data => {
if (data.success === false) {
if(data.errors) {
return setErrors(data.errors);
}
if(data.single_error) {
return setErrors([...errors, data.single_error]);
}
}
if(data.success === true) {
setErrors([]);
//Redirect to login
console.log("Success");
}
})
}
return(
<div className="login register">
<h1>Register</h1>
<form onSubmit={handleFormSubmit}>
<label>
<i className="fa fa-user-o" aria-hidden="true"></i>
</label>
<input type="text" name="username"
value={username}
onChange={e => setUsername(e.target.value)}
placeholder="Username" id="username" required />
<label>
<i className="fa fa-unlock-alt" aria-hidden="true"></i>
</label>
<input type="password" name="password"
value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Password" id="password" required />
{errors ? errors.map((item, key) => (
// <li key={key}>{item}</li>
console.log(item)
)) : null}
<input type="submit" value="Register" />
</form>
<Link className="register-link" to="/"><small>Login 🠖</small></Link>
</div>
)
}
export default RegisterForm;
Any ideas why this will console.log but won't print the data on the screen?
Here is a screenshot of my console.log values: https://prnt.sc/ig6F2O1S1L1L
If I try to map through the array and return the values in a list I don't get any errors just nothing happens.
The <li> HTML element is used to represent an item in a list. It must be contained in a parent element: an ordered list (<ol>), an unordered list (<ul>), or a menu (<menu>).
<ul>
{errors ? errors.map((item, key) => (
<li key={key}>{item}</li>
//console.log(item)
)) : null}
</ul>
Here is the code:
import React from 'react';
class EditEntry extends React.Component {
constructor(props) {
super(props);
this.state = {
entry: '',
description: '',
item: [],
error: null
};
this.handleChangeEntry = this.handleChangeEntry.bind(this);
this.handleChangeDescription = this.handleChangeDescription.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
const { match: { params } } = this.props;
const { id } = params;
fetch(`/api/entries/${id}`, {
method: 'GET'
})
.then(response => response.json())
.then(
data => {
this.setState({
item: data
});
},
error => {
this.setState({
error
});
});
}
handleChangeEntry(e) {
this.setState({ entry: e.target.value });
}
handleChangeDescription(e) {
this.setState({ description: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
const { entry, description } = this.state;
const { match: { params } } = this.props;
const { id } = params;
fetch(`/api/entries/${id}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(entry, description)
})
.then(response => {
if (response.ok) {
window.location.assign("/");
} else {
throw new Error('No response.');
}
},
error => {
this.setState({
error
});
});
}
render() {
const { item } = this.state;
const itemEditForm = item.map(i => {
return <div key={i.id}>
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="entry">Entry</label>
<input
id="entry"
name="entry"
type="text"
className="form-control"
required
value={i.entry}
onChange={this.handleChangeEntry} />
</div>
<div className="form-group">
<label htmlFor="description">Description</label>
<textarea
id="description"
name="description"
type="text"
className="form-control"
required
rows="5"
value={i.description}
onChange={this.handleChangeDescription} />
</div>
<button type="submit" className="btn btn-secondary btn-sm mb-sm-2">Submit</button>
</form>
</div>
});
return (
<div>
{itemEditForm}
</div>
);
}
}
export default EditEntry;
I can't edit the data contained in:
<input id="entry" (...) />
<textarea id="description" (...) />
There is data, there is a cursor, but these fields are disabled for editing.
I fetch an array with one object from the database (componentDidMount()). I know there is another way to access the data contained in an object. But that way in this project doesn't work. Although in my another project it works. Strange.
You are setting the "entry" and "description" properties in the onChange handler methods. but using the i.entry and i.description in the value property of the input. Please try changing it and maybe if you have multiple items in the item array, you can try something like below to handle state.
Component:
<input
id="name"
name="name"
type="text"
className="form-control"
required
value={i.name}
onChange={(e) => this.handleChangeName(e, i.id)}
/>
JS:
handleChangeName(e, id) {
console.log(e.target.value);
const newState = {
item: this.state.item.map((x) =>
x.id != id ? x : { id: id, name: e.target.value }
)
};
this.setState(newState);
}
Also, please find a working example based on your code on the CodeSandbox Link
Thanks.
index.js
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import { ToastContainer, toast } from 'react-toastify';
import { useHistory } from 'react-router-dom';
import 'react-toastify/dist/ReactToastify.css';
const AddRequest = () => {
const [request, setRequest] = useState({
product_name: '',
description: '',
product_img: '',
});
const [error, setError] = useState({
product_error: ''
})
const handleChange = e => {
e.preventDefault();
const {name, value} = e.target;
let formError = {...error};
switch(name) {
case "product_error":
formError.product_error =
value.length < 0 ? "Required" : "";
break;
default:
break;
}
setError({formError, [name]: value});
console.log(error)
setRequest({ ...request, [e.target.name]: e.target.value });
};
const headers = {
'x-access-token': localStorage.getItem('accessToken'),
'content-type': 'multipart/form-data'
}
const handleImageChange = async e => {
e.preventDefault();
setRequest({ ...request, [e.target.name]: e.target.files });
};
const handleSubmit = async e => {
e.preventDefault();
const formData = new FormData()
for (const file of request.product_img) {
formData.append('product_img', file)
}
formData.append('product_name', request.product_name)
formData.append('description', request.description)
await Axios.post(config.api, formData, {
headers: headers
})
.then(res => {
toast.success('Added Successfully!', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
.catch(e => {
console.log(e)
toast.error('not Added', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
setTimeout(function () {
history.push('/')
}, 1500);
};
return (
<>
<ToastContainer />
<form onSubmit={e => handleSubmit(e)} noValidate>
<div className="form-group">
<label htmlFor='product_name'>Product Name:</label>
<input type="text" name="product_name" id="product_name" placeholder="Enter Product Name" className="form-control" noValidate onChange={e => handleChange(e)} />
{errors.product_error}
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='description'>Description:</label>
<input type="text" name="description" id="description" placeholder="Description" className="form-control" onChange={e => handleChange(e)} />
</div>
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='product_img'>Product Image:</label> <br />
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} />
</div>
<button type="submit" className="btn btn-success"> Add Request Rekko </button>
</form>
</>
)
};
export default AddRequest
Everything is working fine but form validation is not working. I am new to react and tried many things but still, it is not working. Can anyone help me with form validation? I only want all 3 fields to be required. It shows the message that this field is required if someone submits a form without entering anything.
You can simply add the tag required inside the input, like this:
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} required />