I'm changing React Class into function for a component with text and number input from database (mongodb). The function handleInputChange works fine for input text and number, but not with the slider. Don't know, how to solve. TypeError: Cannot destructure property 'name' of 'event.target' as it is undefined.
const ProgrammUpdate = props => {
const {id} = useParams();
const initialProgrammState = {
id: null,
title: "",
description: "",
volume_left: "",
volume_right: "",
}
const [currentProgramm, setCurrentProgramm] = useState(initialProgrammState);
const {user} = ChatState();
const toast = useToast();
const history = useHistory();
const [message, setMessage] = useState("");
const bg = useColorModeValue('brand.200', 'brand.100')
const color = useColorModeValue('gray.800', 'white')
const getProgramm = programmId => {
HoerprogrammDataService.get(programmId)
.then(response => {
setCurrentProgramm(response.data);
console.log(response.data);
})
.catch(e => {
console.log(e);
})
}
useEffect(() => {
if (id)
getProgramm(id);
// eslint-disable-next-line
console.log(id)
}, [id]);
const handleInputChange = event => {
const {name, value} = event.target;
setCurrentProgramm({...currentProgramm, [name]: value});
};
const updateProgramm = () => {
HoerprogrammDataService.update(id, currentProgramm)
.then(response => {
console.log(response.data);
// setMessage("The tutorial was updated successfully!");
history.push('/programme');
})
.catch(e => {
console.log(e);
});
};
const deleteProgramm = () => {
HoerprogrammDataService.delete(currentProgramm.id)
.then(response => {
console.log(response.data);
history.push('/programme');
})
.catch(e => {
console.log(e);
});
};
return<LandingLayout>
<h2>Test</h2>
{currentProgramm ? (<>
<Input
placeholder={currentProgramm.title} size='md'
type="text"
className="form-control"
id="title"
required
value={currentProgramm.title}
onChange={handleInputChange}
name="title"
/>
<Input
placeholder={currentProgramm.volume_left}
type="text"
className="form-control"
id="volume_left"
value={currentProgramm.volume_left}
onChange={handleInputChange}
name="volume_left"
/>
<Slider
flex='1'
value={currentProgramm.volume_left}
onChange={handleInputChange}
orientation='horizontal'
minH='20'
name="volume_left"
min={0} max={10} step={1}
>
<SliderMark value={0} mt='12' ml='-1.5' fontSize='md'>0</SliderMark>
<SliderMark value={5} mt='12' ml='-1.5' fontSize='md'>5</SliderMark>
<SliderMark value={10} mt='12' ml='-1.5' fontSize='md'>10</SliderMark>
<SliderTrack bg='blue.200'>
<SliderFilledTrack bg="blue.400" />
</SliderTrack>
<SliderThumb bg="blue.400" fontSize='md' boxSize='40px' children={currentProgramm.volume_left}>{currentProgramm.volume_left}</SliderThumb>
</Slider>
<Routelink to={"/programme"} className={"nav-link"}>
<Button variant={ "outline"} colorScheme={"red"}>Abbruch</Button>
</Routelink>
<button className="badge badge-danger mr-2" onClick={deleteProgramm}>
Delete
</button>
<button
type="submit"
className="badge badge-success"
onClick={updateProgramm}
>
Update
</button>
<p>{message}</p>
</>
) : (
<Box d="flex" alignItems="center" justifyContent="center" h="100%">
<Text fontSize="3xl" pb={3} fontFamily="Work sans">Programm nicht geladen</Text>
</Box>
)}
</LandingLayout>
}
export default ProgrammUpdate;
You were getting this error because Slider onChange method passes the actual value, not the event object. On the other hand, the Input onChange method passes the event.
Your Slider onChange method will look something like this-
const handleSliderChange = (val) => {
setCurrentProgramm({...currentProgramm, volume_left: val})
}
Related
Below are 2 files that is expected to display details in a form, name, service, date, cost. The problem is that it doesn't display information entered in other input fields when I choose a future date. Whereas when I use the current date, it displays the information entered in other input fields as expected. Why is this the case please and how do i fix it?
import { useState, useEffect } from 'react';
import axios from 'axios';
const ConfirmBooking = () => {
//track state
const [data,setData] = useState([])
const Style = {
color: 'rgb(97, 113, 154)',
padding: '5px'
}
//GET data
useEffect(() => {
axios
.get('http://localhost:5000/api/bookings')
.then(res => {
console.log(res)
setData(res.data)
})
.catch(err => {
console.log(err)
})
}, [])
//DELETE data
const deleteHandler =(id) =>{
axios
.delete('http://localhost:5000/api/bookings/'+id)
.then(res => {
console.log(res.data);
}
)
.catch(error =>{
console.log(error)
})
}
if(!data?.length) return <div>loading...</div>
return (
<div className='bookings'>
<h4 style={Style}>Name:{" "}{data.at(-1).name}</h4>
<h4 style={Style} >Service:{" "}{data.at(-1).service}</h4>
<h4 style={Style} >Date:{" "}{data.at(-1).date}</h4>
<h4 style={Style} >Cost:{" "}{data.at(-1).cost}</h4><br></br>
<button className='Btn'>Edit</button>
<button className='Btn' onClick={ () => deleteHandler(data.at(-1))} >Delete</button>
</div>
)
}
export default ConfirmBooking;
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom'
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
const Form = () => {
const navigate = useNavigate();
const [myState, setMyState] = useState({
name: "",
service: "finance",
date: new Date(),
cost: "3$"
});
//event to handle all inputs except datepicker
const handleChange = (e)=> {
// const { name, value} = e.target;
const name = e.target.name;
const value = e.target.value
//to update the input myState
setMyState
({...myState, [name]: value });
}
const handleDateChange = (date) => {
setMyState({
date:date
})
}
const handleSubmit = (e) => {
e.preventDefault();
if (myState !== "") {
alert('booking success')
}
//Add data to database
axios.post('http://localhost:5000/api/bookings', myState)
.then(res => {
setMyState
(res.data);
console.log(res);
//redirect to another page
navigate('/ConfirmBooking')
})
.catch((error) => {
console.log(error)
})
}
return (
<form className='form' onSubmit={handleSubmit} >
<h2 className="headerForm">Create appointment</h2>
<div className="mb-3">
<label className="form-label">Name</label>
<input name='name' type="text" className="form-control" id="exampleFormControlInput1" value={myState.name} onChange={handleChange} />
<label className="form-label">Service</label>
<input name='service' type="text" className="form-control " id="exampleFormControlInput1" value={myState.service} onChange={handleChange} />
<label className="form-label"> Date</label>
<div>
<DatePicker
selected={myState.date}
onChange={handleDateChange}
startDate = {new Date()}
minDate={new Date()}
filterDate={date => date.getDay() !== 6 && date.getDay() !== 0}
/>
</div>
<label className="form-label">Cost</label>
<input name='cost' type="text" className="form-control" id="exampleFormControlInput1" value={myState.cost} onChange={handleChange} />
</div>
<button >Submit</button>
</form>
)
}
export default Form;
This method is changing the state without other properties:
...
const handleDateChange = (date) => {
setMyState({
date:date
})
}
...
If you want to change this property from state, you need to destructure previous value and change date.
const handleDateChange = (date) => {
setMyState({
...myState,
date:date
})
}
I need to update the state on main page, the problem is that I update values 3 levels down...
This component is where I get all the cities, putting the data on the State and map through cities.
CitiesPage.tsx
export const CitiesPage = () => {
const [cities, setCities] = useState<City[]>([]);
useEffect(() => {
getCities().then(setCities);
}, []);
return (
<>
<PageTitle title="Cities" />
<StyledCitySection>
<div className="headings">
<p>Name</p>
<p>Iso Code</p>
<p>Country</p>
<span style={{ width: "50px" }}></span>
</div>
<div className="cities">
{cities.map((city) => {
return <CityCard key={city.id} city={city} />;
})}
</div>
</StyledCitySection>
</>
);
};
On the next component, I show cities and options to show modals for delete and update.
CityCard.tsx.
export const CityCard = ({ city }: CityProps) => {
const [showModal, setShowModal] = useState(false);
const handleModal = () => {
setShowModal(true);
};
const handleClose = () => {
setShowModal(false);
};
return (
<>
{showModal && (
<ModalPortal onClose={handleClose}>
<EditCityForm city={city} closeModal={setShowModal} />
</ModalPortal>
)}
<StyledCityCard>
<p className="name">{city.name}</p>
<p className="isoCode">{city.isoCode}</p>
<p className="country">{city.country?.name}</p>
<div className="options">
<span className="edit">
<FiEdit size={18} onClick={handleModal} />
</span>
<span className="delete">
<AiOutlineDelete size={20} />
</span>
</div>
</StyledCityCard>
</>
);
};
and finally, third levels down, I have this component.
EditCityForm.tsx.
export const EditCityForm = ({ city, closeModal }: Props) => {
const [updateCity, setUpdateCity] = useState<UpdateCity>({
countryId: "",
isoCode: "",
name: "",
});
const handleChange = (
evt: ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
const { target } = evt;
setUpdateCity({ ...updateCity, [target.name]: target.value });
};
const handleSubmit = (evt: FormEvent<HTMLFormElement>) => {
evt.preventDefault();
const { id: cityId } = city;
updateCityHelper(cityId, updateCity);
closeModal(false);
};
useEffect(() => {
setUpdateCity({
isoCode: city.isoCode,
name: city.name,
countryId: city.country?.id,
});
}, [city]);
return (
<form onSubmit={handleSubmit}>
<Input
label="Iso Code"
type="text"
placeholder="Type a IsoCode..."
onChange={handleChange}
name="isoCode"
value={updateCity.isoCode}
/>
<Input
label="Name"
type="text"
placeholder="Paste a Name.."
onChange={handleChange}
name="name"
value={updateCity.name}
/>
<CountrySelect
label="Country"
onChange={handleChange}
value={city.country?.name || ""}
name="countryId"
/>
<Button type="submit" color="green" text="Update" />
</form>
);
};
Edit form where retrieve data passed from CityCard.tsx and update State, passing data to a function that update Info, closed modal and... this is where I don't know what to do.
How can I show the info updated on CitiesPage.tsx when I submitted on EditCityForm.tsx
Any help will be appreciated.
Thanks!
You are storing the updated value in a different state, namely the updateCity state, but what you should be doing is update the origional cities state. While these two states are not related, and at the same time your UI is depend on cities state's data, so if you wish to update UI, what you need to do is update cities' state by using it's setter function setCities.
Just like passing down state, you pass it's setters as well, and use the setter function to update state's value:
// CitiesPage
{cities.map((city) => {
return <CityCard key={city.id} city={city} setCities={setCities} />;
})}
// CityCard
export const CityCard = ({ city, setCities }: CityProps) => {
// ...
return (
// ...
<ModalPortal onClose={handleClose}>
<EditCityForm city={city} closeModal={setShowModal} setCities={setCities} />
</ModalPortal>
// ...
)
}
// EditCityForm
export const EditCityForm = ({ city, closeModal, setCities }: Props) => {
// const [updateCity, setUpdateCity] = useState<UpdateCity>({ // no need for this
// countryId: "",
// isoCode: "",
// name: "",
// });
const handleSubmit = (evt: FormEvent<HTMLFormElement>) => {
evt.preventDefault();
const { id: cityId } = city;
setCities(); // your update logic
closeModal(false);
};
}
I'd advise you to use React-Redux or Context API whenever you have nested structures and want to access data throughout your app.
However in this case you can pass setCities and cities as a prop to CityCard and then pass this same prop in the EditCityForm component and you can do something like this in your handleSubmit.
const handleSubmit = (evt: FormEvent<HTMLFormElement>) => {
evt.preventDefault();
let updatedCities = [...cities];
updatedCities.forEach(el => {
if(el.id == updateCity.id) {
el.countryCode = updateCity.countryCode;
el.name = updateCity.name;
el.isoCode = updateCity.isoCode;
}
})
setCities(updatedCities);
closeModal(false);
};
I need to save the username in my Firestore Database while creating the user. I'm using Firebase (v9) with React. The code is Below.
A user is created but in the Firestore Database user is not added.
What is the way to use setDoc inside createUserWithEmailAndPassword
Can someone help me with the code?
import Box from "#mui/material/Box";
import OutlinedInput from "#mui/material/OutlinedInput";
import Button from "#mui/material/Button";
import Alert from "#mui/material/Alert";
import { Link, Outlet } from "react-router-dom";
import {
collection,
query,
onSnapshot,
setDoc,
serverTimestamp,
doc,
} from "firebase/firestore";
import { createUserWithEmailAndPassword } from "firebase/auth";
import { db, auth } from "../../../firebase";
import IGLogo from "../../../images/instagram-logo.png";
import "./SignUpForm.scss";
function SignUpForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [username, setUsername] = useState("");
const [successalert, setSuccessAlert] = useState(undefined);
const [failalert, setFailAlert] = useState(undefined);
//const [user, setUser] = useState(undefined);
useEffect(() => {
const timeId = setTimeout(() => {
// After 3 seconds set the show value to false
setSuccessAlert(undefined);
}, 3000);
return () => {
clearTimeout(timeId);
};
});
useEffect(() => {
const timeId = setTimeout(() => {
// After 3 seconds set the show value to false
setFailAlert(undefined);
}, 3000);
return () => {
clearTimeout(timeId);
};
});
useEffect(() => {
const timeId = setTimeout(() => {
// After 3 seconds set the show value to false
setFailAlert(undefined);
}, 3000);
return () => {
clearTimeout(timeId);
};
});
const instagramSignUp = (event) => {
event.preventDefault();
const q = query(collection(db, "users"));
onSnapshot(q, (querySnapshot) => {
querySnapshot.docs.forEach((doc) => {
if (doc.id === username) {
setFailAlert({ type: "userexist" });
} else {
createUserWithEmailAndPassword(auth, email, password)
.then((userCreated) => {
setDoc(doc(db, "users", username), {
timestamp: serverTimestamp(),
})
.then(() => {
setSuccessAlert({ type: "success" });
console.log("user created in collection");
})
.catch((error) => {
console.log(error.message);
});
})
.catch((error) => {
console.log(
"createUserWithEmailAndPassword = " +
error.message
);
});
}
});
});
};
return (
<>
<div className="component__signupalerts">
{successalert?.type === "success" && (
<Alert variant="filled" severity="success">
Account Created Successfully. Please check your Email
for Verification.
</Alert>
)}
{failalert?.type === "userexist" && (
<Alert variant="filled" severity="error">
Username already taken
</Alert>
)}
</div>
<div className="component__signupform">
<img src={IGLogo} alt="" />
<Box component="form" className="component__signupform--box">
<OutlinedInput
className="component__loginform--input"
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<OutlinedInput
className="component__signupform--input"
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<OutlinedInput
className="component__signupform--input"
type="password"
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<Button
className="component__signupform--button"
type="submit"
variant="contained"
onClick={instagramSignUp}
>
Sign Up
</Button>
<Link to="/" className="component__signupform--button">
Sign In
</Link>
</Box>
</div>
<Outlet />
</>
);
}
export default SignUpForm;
Console.log "doc is not a function"
The problem is that you have two definitions of doc in your code:
First you import { ...., doc, ... } from "firebase/firestore";.
Then you also define it in querySnapshot.docs.forEach((doc) => {.
The doc in that second line hides the one that you imported.
The easiest fix is to name the variable of forEach something else:
onSnapshot(q, (querySnapshot) => {
querySnapshot.docs.forEach((docSnapshot) => {
if (docSnapshot.id === username) {
...
I would like to upload a image-file to storage of the firebase and put {title , content, createDate etc} in firestore.
but it seems that state.upload file prevents putting it in firestore.
this.setState({ uploadfile: "" })
The error says
FirebaseError: Function addDoc() called with invalid data. Unsupported field value: a custom File object (found in field uploadfile in document projects/c0hQXdRAgIe1lIzq1vTy)
class CreateProject extends Component {
state = {
title:'',
content:'',
uploadfile:'',
setImageUrl:'',
}
handleChange = (e) =>{
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = (e) =>{
e.preventDefault();
this.setState({ uploadfile: "" })
this.props.createProject(this.state)
this.props.history.push('/')
}
onDrop = acceptedFiles => {
if (acceptedFiles.length > 0) {
this.setState({ uploadfile: acceptedFiles[0] })
}
}
handleSubmitImg = (e) =>{
e.preventDefault()
//this.props.sampleteFunction()
};
parseFile = (file) =>{
const updatedFile = new Blob([file], { type: file.type });
updatedFile.name = file.name;
return updatedFile;
}
onSubmit = (event) => {
event.preventDefault();
var updatedFile = this.state.uploadfile;
if (updatedFile === "") {
}
console.log("aaaaaaaaaaaa"+updatedFile)
const uploadTask = storage.ref(`/images/${updatedFile.name}`).put(updatedFile);
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
this.next,
this.error,
this.complete
);
};
next = snapshot => {
const percent = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
};
error = error => {
console.log(error);
};
complete = () => {
var updatedFile = this.state.uploadfile
storage
.ref("images")
.child(updatedFile.name)
.getDownloadURL()
.then(fireBaseUrl => {
this.setState({ setImageUrl: fireBaseUrl })
//this.state.setImageUrl(fireBaseUrl);
});
};
render() {
const maxSize = 3 * 1024 * 1024;
const dropzoneStyle = {
width: "100%",
height: "auto",
borderWidth: 2,
borderColor: "rgb(102, 102, 102)",
borderStyle: "dashed",
borderRadius: 5,
}
const {auth} = this.props
console.log("UP"+this.state.uploadfile );
if(!auth.uid) return <Redirect to="/signin" />
return (
<Dropzone
onDrop={this.onDrop}
accept="image/png,image/jpeg,image/gif,image/jpg"
inputContent={(files, extra) => (extra.reject ? 'Image files only' : 'Drag Files')}
styles={dropzoneStyle}
minSize={1}
maxSize={maxSize}
>
{({ getRootProps, getInputProps }) => (
<div className="container">
<form onSubmit={this.handleSubmit} className="white">
<h5 className="grey-text text-darken-3">
Create Project
</h5>
<div className="input-field">
<label htmlFor="title">Title</label>
<input type="text" id="title" onChange={this.handleChange}/>
</div>
<div className="input-field">
<label htmlFor="content">Project Content</label>
<textarea id="content" className="materialize-textarea" onChange={this.handleChange}></textarea>
</div>
<div className="input-field">
<button className="btn pink lighten-1 z-depth-0">Create</button>
</div>
</form>
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>File Drag</p>
{this.state.uploadfile ? <p>Selected file: {this.state.uploadfile.name}</p> : null}
{this.state.uploadfile ? (<Thumb key={0} file={this.state.uploadfile } />) :null}
</div>
<form onSubmit={this.onSubmit}>
<button>Upload</button>
</form>
</div>
)}
</Dropzone>
)
}
}
const matchStateToProps = (state) => {
return{
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return{
createProject: (project) => dispatch(createProject(project))
}
}
export default connect(matchStateToProps, mapDispatchToProps)(CreateProject)
Action
export const createProject = (project) => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
// make async call to database
const firestore = getFirestore();
const profile = getState().firebase.profile;
const authorId = getState().firebase.auth.uid;
firestore.collection('projects').add({
...project,
authorUserName: profile.userName,
authorId: authorId,
createdAt: new Date()
}).then(() => {
dispatch({ type: 'CREATE_PROJECT', project})
}).catch((err) => {
dispatch({ type: 'CREATE_PROJECT_ERROR', err })
})
}
};
How Should I solve this problem?
After uploading an image by react state, this state seems to prevents putting props"project" in Action in Redux.
this.setState({ uploadfile: "" })
The error says
FirebaseError: Function addDoc() called with invalid data. Unsupported field value: a custom File object (found in field uploadfile in document projects/c0hQXdRAgIe1lIzq1vTy)
class CreateProject extends Component {
state = {
title:'',
content:'',
uploadfile:'',
setImageUrl:'',
}
handleChange = (e) =>{
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = (e) =>{
e.preventDefault();
this.setState({ uploadfile: "" })
this.props.createProject(this.state)
this.props.history.push('/')
}
onDrop = acceptedFiles => {
if (acceptedFiles.length > 0) {
this.setState({ uploadfile: acceptedFiles[0] })
}
}
handleSubmitImg = (e) =>{
e.preventDefault()
//this.props.sampleteFunction()
};
parseFile = (file) =>{
const updatedFile = new Blob([file], { type: file.type });
updatedFile.name = file.name;
return updatedFile;
}
onSubmit = (event) => {
event.preventDefault();
var updatedFile = this.state.uploadfile;
if (updatedFile === "") {
}
console.log("aaaaaaaaaaaa"+updatedFile)
const uploadTask = storage.ref(`/images/${updatedFile.name}`).put(updatedFile);
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
this.next,
this.error,
this.complete
);
};
next = snapshot => {
const percent = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
};
error = error => {
console.log(error);
};
complete = () => {
var updatedFile = this.state.uploadfile
storage
.ref("images")
.child(updatedFile.name)
.getDownloadURL()
.then(fireBaseUrl => {
this.setState({ setImageUrl: fireBaseUrl })
//this.state.setImageUrl(fireBaseUrl);
});
};
render() {
const maxSize = 3 * 1024 * 1024;
const dropzoneStyle = {
width: "100%",
height: "auto",
borderWidth: 2,
borderColor: "rgb(102, 102, 102)",
borderStyle: "dashed",
borderRadius: 5,
}
const {auth} = this.props
console.log("UP"+this.state.uploadfile );
if(!auth.uid) return <Redirect to="/signin" />
return (
<Dropzone
onDrop={this.onDrop}
accept="image/png,image/jpeg,image/gif,image/jpg"
inputContent={(files, extra) => (extra.reject ? 'Image files only' : 'Drag Files')}
styles={dropzoneStyle}
minSize={1}
maxSize={maxSize}
>
{({ getRootProps, getInputProps }) => (
<div className="container">
<form onSubmit={this.handleSubmit} className="white">
<h5 className="grey-text text-darken-3">
Create Project
</h5>
<div className="input-field">
<label htmlFor="title">Title</label>
<input type="text" id="title" onChange={this.handleChange}/>
</div>
<div className="input-field">
<label htmlFor="content">Project Content</label>
<textarea id="content" className="materialize-textarea" onChange={this.handleChange}></textarea>
</div>
<div className="input-field">
<button className="btn pink lighten-1 z-depth-0">Create</button>
</div>
</form>
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>File Drag</p>
{this.state.uploadfile ? <p>Selected file: {this.state.uploadfile.name}</p> : null}
{this.state.uploadfile ? (<Thumb key={0} file={this.state.uploadfile } />) :null}
</div>
<form onSubmit={this.onSubmit}>
<button>Upload</button>
</form>
</div>
)}
</Dropzone>
)
}
}
const matchStateToProps = (state) => {
return{
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return{
createProject: (project) => dispatch(createProject(project))
}
}
export default connect(matchStateToProps, mapDispatchToProps)(CreateProject)
Action
export const createProject = (project) => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
// make async call to database
const firestore = getFirestore();
const profile = getState().firebase.profile;
const authorId = getState().firebase.auth.uid;
firestore.collection('projects').add({
...project,
authorUserName: profile.userName,
authorId: authorId,
createdAt: new Date()
}).then(() => {
dispatch({ type: 'CREATE_PROJECT', project})
}).catch((err) => {
dispatch({ type: 'CREATE_PROJECT_ERROR', err })
})
}
};