Uploading and displaying image - ReactJs, Node.js - javascript

App is running on Node.js and React. In database (mongodb used) I have collection Rooms that contains details about particular room.
I have an option to add new room and there is an option to upload image for that particular room.
Here is code for room model.
SERVER PART
UserModel.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Define our model
const roomSchema = new Schema({
title: { type: String },
description: { type: String },
price: { type: Number },
room_type: { type: String },
nb_guests: { type: Number },
imageData: {type: String}
});
// Create the model class
const ModelClass = mongoose.model('room', roomSchema);
// Export the model
module.exports = ModelClass;
This is add route:
room.route.js
// Defined store route
roomRoutes.route('/add').post(function (req, res) {
let room = new Room(req.body);
room.save()
.then(room => {
res.status(200).json({'room': 'room is added successfully'});
})
.catch(err => {
res.status(400).send("unable to save to database");
});
});
And here is form where I add new room:
CreateRoom.js
export default class CreateRoom extends React.Component {
constructor(props) {
super(props);
this.onChangeTitle = this.onChangeTitle.bind(this);
this.onChangeDescription = this.onChangeDescription.bind(this);
this.onChangePrice = this.onChangePrice.bind(this);
this.onChangeGuests = this.onChangeGuests.bind(this);
this.onChangeRoomType = this.onChangeRoomType.bind(this);
this.onImageUpload = this.onImageUpload.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
title: '',
description: '',
price: '',
room_type: '',
nb_guests: '',
imageData: ''
}
}
onChangeTitle(e) {
console.log('title changed');
this.setState({
title: e.target.value
});
}
onChangeDescription(e) {
console.log('description changed');
this.setState({
description: e.target.value
});
}
onChangePrice(e) {
console.log('price changed');
this.setState({
price: e.target.value
});
}
onChangeGuests(e) {
console.log('guests changed');
this.setState({
nb_guests: e.target.value
});
}
onChangeRoomType(e) {
console.log('room changed');
this.setState({
room_type: e.target.value
});
}
onImageUpload = event => {
console.log('picture updated');
this.setState({
imageData: event.target.files[0]
});
}
onSubmit(e) {
e.preventDefault();
console.log(`Form submitted:`);
const newRoom = {
title: this.state.title,
description: this.state.description,
price: this.state.price,
nb_guests: this.state.nb_guests,
room_type: this.state.room_type,
imageData: this.state.imageData
}
axios.post('http://localhost:3090/admin/add', newRoom)
.then(res => console.log(res.data));
this.setState({
title: '',
description: '',
price: '',
room_type: '',
nb_guests: '',
imageData: ''
})
}
render() {
return (
<div>
<Header />
<div style={{ marginTop: 20 }}>
<div className="album py-5 bg-light">
<div className="container">
<h1 class="h3 mb-3 font-weight-bold">Create new room</h1>
<p>Provide all needed details</p>
<div className="row"></div>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label htmlFor="title" className="col-form-label">Title:</label>
<input
type="text"
value={this.state.title}
onChange={this.onChangeTitle}
className="form-control" id="title" />
</div>
<div className="form-group">
<label htmlFor="message-text" className="col-form-label">Description:</label>
<textarea
type="text"
value={this.state.description}
onChange={this.onChangeDescription}
className="form-control" id="description"></textarea>
</div>
<div className="form-group">
<label htmlFor="title" className="col-form-label">Price:</label>
<input
type="text"
value={this.state.price}
onChange={this.onChangePrice}
className="form-control" id="price" />
</div>
<div className="form-group">
<label htmlFor="exampleFormControlSelect1">Number of guests:</label>
<select onChange={this.onChangeGuests} className="form-control" id="exampleFormControlSelect1">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
</div>
<div className="form-group">
<label htmlFor="exampleFormControlSelect1">Room type:</label>
<select onChange={this.onChangeRoomType} className="form-control" id="exampleFormControlSelect1">
<option>Single</option>
<option>Double</option>
<option>Apartment</option>
</select>
</div>
<div class="form-group">
<label for="exampleFormControlFile1">Upload photo</label>
<input type="file" onChange={this.imageUpload} class="form-control-file" id="exampleFormControlFile1" />
</div>
<br />
<div className="form-group">
<input type="submit" value="Create room" className="btn btn-primary" />
</div>
</form>
</div>
</div>
</div>
</div>
)
}
}
After clicking on Create Room button data is added to database and "something" is added to imageData field in room collection but I think not correctly.
I am trying to display it on LandingPage like this:
LandingPage.js
const Room = props => (
<div className = "col-md-4" >
<div className="card mb-4 shadow-sm">
<img src={props.room.imageData} class="card-img-top" alt="..." width="100%" height="225" />
<div className="card-body">
<h5 class="card-title">{props.room.title}</h5>
<p className="card-text">{props.room.description}</p>
<div className="d-flex justify-content-between align-items-center">
<div className="btn-group">
<Link className="btn btn-sm btn-outline-secondary" to={"/view/"+props.room._id}>View</Link>
</div>
</div>
</div>
</div>
</div >
)
export default class LandingPage extends React.Component {
constructor(props) {
super(props);
this.state = {
rooms: [],
term:''
}
this.onSearchHandler = this.onSearchHandler.bind(this);
}
componentDidMount() {
axios.get('http://localhost:3090/admin/')
.then(response => {
this.setState({
rooms: response.data
})
.catch(function (error) {
console.log(error);
})
})
}
roomList = () => {
const { rooms, term } = this.state;
if (!term) {
return rooms.map(function(currentRoom, i) {
return <Room room={currentRoom} key={i} />;
});
} else {
return rooms
.filter(room => {
return room.nb_guests === term;
})
.map(matchingRoom => {
return <Room room={matchingRoom} />;
});
}
};
onSearchHandler = e => {
this.setState({
term: parseFloat(e.target.value)
});
};
render() {
return (
<div>
<LPheader />
<Carousel />
<div>
<div className="album py-5 bg-light">
<div className="container">
<div className="row">
<form>
<input
type="text"
onChange={this.onSearchHandler}
value={this.state.term}
/>
</form>
{this.roomList()}
</div>
</div>
</div>
</div>
</div>
)
}
}
Using this line of code I am trying to display it but it's not working:
<img src={props.room.imageData} class="card-img-top" alt="..." width="100%" height="225" />
I am not sure am I maybe uploading it wrong to database or am I displaying it wrong.
I have no error but image is just not being displayed.
Any tip is highly appreciated.

Just as you expected it is about the image not being handled correctly, what you saved to the database is the binary of the image represented as text (this might even cause corruption to the image) you need to handle saving the image yourself, and you have two options here:
1) You decide to save the image as a string, and then before saving the image you need to decode it to base64 to ensure that the database does not corrupt it's data, after that you display it directly in the image src, your image src should look something like this
<img src="data:image/png;base64, {base64data==}" />
2) You decide to save the image as file in your webserver, and you handle the link to the file to the image in the image src
I assume that there is some utility for your server out there that do one of the previous steps for you/ or do both depending on the image size. If you don't want to implement that yourself

Related

Save data and image in table

I'm trying to save information in a table, which also has a field of type varbinary(max) (an image) (SQL Server)
class AddDoctor extends Component {
state = {
file: null,
name: "",
phoneNumber: "",
email: "",
status: "Active",
specialty: "",
specialities: [],
};
componentDidMount() {
const URL = "http://localhost:55317/api/TSpecialties";
ApiService.get(URL)
.then((data) => this.setState({ specialities: data }))
.catch((err) => console.log(err));
}
imgClick = () => {
const file = document.querySelector("#id-file");
file.click();
};
handleChange = (e) => {
const state = this.state;
state[e.target.name] = e.target.value;
this.setState({
...state,
});
};
handleFileChange = (event) => {
this.setState({
file: URL.createObjectURL(event.target.files[0]),
});
};
handleSubmit = (e) => {
e.preventDefault();
const URL = "http://localhost:55317/api/TDoctors/";
const DATA = {
doctorName: this.state.name,
doctorProfileImg: this.state.file,
doctorPhoneNumber: this.state.phoneNumber,
doctorEmail: this.state.email,
doctorStatus: this.state.status,
doctorSpecialtyId: Number(this.state.specialty),
};
let formData = new FormData();
formData.append("doctorProfileImg", DATA.doctorProfileImg);
formData.append("doctorName", DATA.doctorName);
formData.append("doctorEmail", DATA.doctorEmail);
formData.append("doctorPhoneNumber", DATA.doctorPhoneNumber);
formData.append("doctorStatus", DATA.doctorStatus);
formData.append("doctorSpecialtyId", DATA.doctorSpecialtyId);
const options = {
method: "POST",
body: formData
};
fetch(URL, options)
.then(res => console.log(res))
.catch(err => console.log("ERR: " + err))
};
render() {
return (
<div>
<form className="row g-3" onSubmit={this.handleSubmit}>
<div className="col-md-6">
<label htmlFor="name" className="form-label">
Name
</label>
<input
type="text"
className="form-control"
id="name"
name="name"
onChange={this.handleChange}
placeholder="Input your name"
/>
</div>
<div className="col-md-6">
<label htmlFor="email" className="form-label">
Email
</label>
<input
type="text"
onChange={this.handleChange}
name="email"
className="form-control"
id="email"
/>
</div>
<div className="col-md-6">
<label className="mb-2" htmlFor="phoneNumber">
Phone Number
</label>
<div className="input-group mb-2 mr-sm-2">
<div className="input-group-prepend">
<div className="input-group-text">+51</div>
</div>
<input
type="text"
onChange={this.handleChange}
className="form-control"
id="phoneNumber"
name="phoneNumber"
placeholder="Phone Number"
/>
</div>
</div>
<div className="col-md-12">
<label htmlFor="specialty" className="form-label">
Specialty
</label>
{/* */}
<select
id="specialty"
name="specialty"
onChange={this.handleChange}
className="form-select"
>
<option defaultValue>Choose...</option>
{this.state.specialities.map((sp) => (
<option value={sp.specialtyId}>
{sp.specialtyName}
</option>
))}
</select>
{/* */}
</div>
<div className="col-12 my-5">
<button
type="submit"
className="btn btn-outline-success w-100"
>
Save
</button>
</div>
</form>
<div className="col mx-5" style={{ minWidth: "250px" }}>
<img
src={ this.state.file}
id="img-select"
onClick={this.imgClick}
className="img-fluid img-thumbnail"
alt="doctor-img"
/>
<input
type="file"
style={{ display: "none" }}
onChange={this.handleFileChange}
id="id-file"
/>
</div>
</div>
);
}
}
Controller POST:
// POST: api/TDoctors
[HttpPost]
public async Task<IActionResult> PostTDoctor([FromBody] TDoctor tDoctor)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.TDoctor.Add(tDoctor);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTDoctor", new { id = tDoctor.DoctorId }, tDoctor);
}
response on console developer tools when submit form:
and...
I have searched a lot of information and I cannot find the solution. I tried placing the multipart/form-data and it doesn't work either. I hope you can help me please.
Saving binary data to a SQL table is not a good practice, please use Azure Blob storage or some other storage service to store the files and just save the path of the file in the database column of a table

Following a tutorial but onSumbit(e) not printing to console

I am following along with this tutorial (https://medium.com/#beaucarnes/learn-the-mern-stack-by-building-an-exercise-tracker-mern-tutorial-59c13c1237a1) and am trying to print to console through the onSubmit function but this is not occurring and I do not know why. I've made sure to use the bind method, and everything seems to be referenced correctly. What am I missing here?
import React, {Component} from 'react';
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
export default class CreateWorkout extends Component {
constructor(props) {
super(props); // Refers to the parent class constructorq
this.onChangeUsername = this.onChangeUsername.bind(this);
this.onChangeDescription = this.onChangeDescription.bind(this);
this.onChangeReps = this.onChangeReps.bind(this);
this.onChangeDuration = this.onChangeDuration.bind(this);
this.onChangeDate = this.onChangeDate.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
username:'',
description: '',
reps: 0,
duration: 0,
date: new Date(),
users: []
}
}
componentDidMount() { // Invoked immediately after a component is mounted
this.setState({
users: ['test user'],
username: 'test user'
});
}
onChangeUsername(e) {
this.setState({
username: e.target.value
});
}
onChangeDescription(e) {
this.setState({
description: e.target.value
});
}
onChangeReps(e) {
this.setState({
reps: e.target.value
});
}
onChangeDuration(e) {
this.setState({
duration: e.target.value
});
}
onChangeDate(date) { // Need to add a date picker library for this
this.setState({
date: date
});
}
// Submit method for submitting an event of the form...
onSubmit(e) {
e.preventDefault();
const workout = {
username: this.state.username,
description: this.state.description,
reps: this.state.reps,
duration: this.state.duration,
date: this.state.date,
};
console.log(workout);
window.location = '/'; // After form is submitted, the location is updated so the user is taken back to the home page
}
render() {
return (
<div>
<h3>Create New Workout Log</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username: </label>
<select ref="userInput" required className="form-control" value={this.state.username} onChange={this.onChangeUsername}>
{
this.state.users.map(function(user) {
return <option key={user} value={user}>{user}</option>;
})
}
</select>
</div>
<div className="form-group">
<label>Description: </label>
<input type="text" required className="form-control" value={this.state.description} onChange={this.onChangeDescription}/>
</div>
<div className="form-group">
<label>Reps: </label>
<input type="text" className="form-control" value={this.state.reps} onChange={this.onChangeReps}/>
</div>
<div className="form-group">
<label>Duration: </label>
<input type="text" className="form-control" value={this.state.duration} onChange={this.onChangeDuration}/>
</div>
<div className="form-group">
<label>Date: </label>
<div><DatePicker selected={this.state.date} onChange={this.state.onChangeDate}/></div>
</div>
<div className="form-group">
<input type="submit" value="Create Workout Log" className="btn btn-primary"/>
</div>
</form>
</div>
);
}
}

Reactjs Dynamic Form Getting Error OnChnage input value?

I am created a dynamic form in react.js but i can not type anything value in input because onchnage function not working i don't know why i tried a lot of times but i am getting failed and adding form and deleting form is working all right only input value not working here is my code and codesandbox link https://codesandbox.io/s/reactdynamicform-02cho .
import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputFields: [
{
firstName: "",
lastName: ""
}
]
};
}
handleAddFields = () => {
const values = this.state.inputFields;
values.push({ firstName: "", lastName: "" });
this.setState({
values
});
};
handleRemoveFields = index => {
const values = this.state.inputFields;
values.splice(index, 1);
this.setState({
values
});
};
async onChange(e, index) {
if (
["firstName","lastName"].includes(e.target.name)
) {
let cats = [...this.state.inputFields];
cats[index][e.target.name] = e.target.value;
await this.setState({
cats
});
}else{
this.setState({ [e.target.name]: e.target.value.toUpperCase() });
}
console.log(this.state.inputFields);
}
handleSubmit = e => {
e.preventDefault();
console.log("inputFields", this.state.inputFields);
};
render() {
return (
<>
<h1>Dynamic Form Fields in React</h1>
<form onSubmit={this.handleSubmit.bind(this)}>
<div className="form-row">
{this.state.inputFields.map((inputField, index) => (
<div key={`${inputField}~${index}`}>
<div className="form-group col-sm-6">
<label htmlFor="firstName">First Name</label>
<input
type="text"
className="form-control"
id="firstName"
name="firstName"
value={inputField.firstName}
onChange={this.onChange.bind(index)}
/>
</div>
<div className="form-group col-sm-4">
<label htmlFor="lastName">Last Name</label>
<input
type="text"
className="form-control"
id="lastName"
name="lastName"
value={inputField.lastName}
onChange={this.onChange.bind(index)}
/>
</div>
<div className="form-group col-sm-2">
<button
className="btn btn-link"
type="button"
onClick={() => this.handleRemoveFields(index)}
>
-
</button>
<button
className="btn btn-link"
type="button"
onClick={() => this.handleAddFields()}
>
+
</button>
</div>
</div>
))}
</div>
<div className="submit-button">
<button
className="btn btn-primary mr-2"
type="submit"
// onSubmit={this.handleSubmit}
>
Save
</button>
</div>
<br />
<pre>{JSON.stringify(this.state.inputFields, null, 2)}</pre>
</form>
</>
);
}
}
export default App;
You approach is not the correct. Use object to contain form values
state = {
inputFields: { firstName: '', lastName: '' }
}
onChange = (e) => {
const { name, value } = e.target;
this.setState(prevState => ({ inputFields: { ...prevState.inputFields, [name]: value } }));
}
// in jsx
<input name="firstName" onChange={this.onChange} />
try this
onChange={(e)=>{this.onChange(e, index)}}
instead of
onChange={this.onChange.bind(index)}
1) Since your inputFields state is an array, you can't just call this.state.inputFields.firstName and even less inputField.firstName.
You have to call this.state.inputsFields[0].firstName.
2) If you want the index AND the event, you have to pass the onChange event like this :
<input
type="text"
className="form-control"
id="lastName"
name="lastName"
onChange={event => this.handleChange(event, index)}
/>
handleChange = (event, index) => {
console.log(event.currentTarget.value, index);
};
// output : {whatever you type} {index of the form}
// exemple : "hello 1"

React Error: Objects are not valid as a React child,If you meant to render a collection of children, use an array instead

i am new to the react when i have done a crud application using React and flux i got this error my codes are below,
UserList
import React, { Component } from "react";
import $ from "jquery";
import UserStore from "../../stores/UserStore";
import * as UserActions from "../../actions/UserActions";
import AddUser from "./AddUser";
$.DataTable = require("datatables.net");
class UserList extends Component {
constructor() {
super();
this.getUsers = this.getUsers.bind(this);
this.state = {
users: UserStore.getAll()
};
this.loadUsers();
}
componentDidMount() {
$(document).ready(function() {
$("#example").DataTable({
ordering: true
});
});
}
componentWillMount() {
UserStore.on("change", this.getUsers);
}
componentWillUnmount() {
UserStore.removeListener("change", this.getUsers);
}
getUsers() {
console.log(" get users called");
this.setState({
users: UserStore.getAll()
});
}
loadUsers() {
UserActions.getUsersList();
}
render() {
const userlistitem = this.state.users.map((user, index) => (
<tr key={index}>
<th scope="row">{index}</th>
<td>{user.name}</td>
<td>{user.username}</td>
<td>{user.email}</td>
<td>{user.dob}</td>
<td>{user.address}</td>
<td>{user.mobile}</td>
<td>{user.branch}</td>
</tr>
));
return (
<div
style={{
marginTop: 80,
marginLeft: 150,
marginRight: 150
}}
>
<div className="card text-white bg-info mb-3">
<div className="card-body">
<div className="d-flex justify-content-between">
<h5>User List</h5>
<div>
<button
style={{
marginTop: 10
}}
type="button"
className="btn btn-light "
data-toggle="modal"
data-target="#exampleModalCenter"
>
Add New User
</button>
</div>
</div>
</div>
</div>
<table id="example" className="table table-bordered table-striped ">
<thead className="thead-dark">
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">User Name</th>
<th scope="col">Email</th>
<th scope="col">DOB</th>
<th scope="col">Address</th>
<th scope="col">Mobile</th>
<th scope="col">Branch</th>
</tr>
</thead>
<tbody>{userlistitem}</tbody>
</table>
<AddUser />
</div>
);
}
}
export default UserList;
Add User
import React, { Component } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import "../../css/datepicker.css";
import * as UserActions from "../../actions/UserActions";
class AddUser extends Component {
constructor(props) {
super(props);
this.state = {
branch: "",
name: "",
username: "",
mobile: "",
email: "",
address: "",
dob: new Date()
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handledatepickerchange = this.handledatepickerchange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({ [name]: value });
}
handledatepickerchange(event) {
this.setState({ dob: event });
}
createUser = () => {
console.log("this is:", this);
const user = {
branch: this.state.branch,
name: this.state.name,
username: this.state.username,
mobile: this.state.mobile,
email: this.state.email,
address: this.state.address,
dob: this.state.dob
};
UserActions.createNewUser(user);
this.setState({
branch: "",
name: "",
username: "",
mobile: "",
email: "",
address: "",
dob: new Date()
});
};
render() {
return (
<div
className="modal fade"
id="exampleModalCenter"
tabIndex="-1"
role="dialog"
aria-labelledby="exampleModalCenterTitle"
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="exampleModalCenterTitle">
Add New User
</h5>
<button
type="button"
className="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
<div className="input-group mb-3">
<input
name="name"
type="text"
className="form-control"
placeholder="Name"
aria-label="Name"
aria-describedby="button-addon2"
value={this.state.name}
onChange={this.handleInputChange}
/>
</div>
<div className="input-group mb-3">
<input
name="username"
type="text"
className="form-control"
placeholder="User Name"
aria-label="User Name"
aria-describedby="button-addon2"
value={this.state.username}
onChange={this.handleInputChange}
/>
</div>
<div className="input-group mb-3">
<input
name="email"
type="email"
className="form-control"
placeholder="Email"
aria-label="Email"
aria-describedby="button-addon2"
value={this.state.email}
onChange={this.handleInputChange}
/>
</div>
<div className="input-group mb-3">
<input
name="address"
type="text"
className="form-control"
placeholder="Address"
aria-label="Address"
aria-describedby="button-addon2"
value={this.state.address}
onChange={this.handleInputChange}
/>
</div>
<div className="input-group mb-3">
<input
name="branch"
type="text"
className="form-control"
placeholder="Branch"
aria-label="Branch"
aria-describedby="button-addon2"
value={this.state.branch}
onChange={this.handleInputChange}
/>
</div>
<div className="input-group mb-3">
<DatePicker
name="dob"
type="text"
className="form-control"
placeholder="DOB"
aria-label="DOB"
aria-describedby="button-addon2"
selected={this.state.dob}
onChange={this.handledatepickerchange}
/>
<p
style={{
marginTop: "5px",
fontWeight: "200",
marginLeft: "10px"
}}
>
Date of Birth(dd/mm/yyyy)
</p>
</div>
<div className="input-group mb-3">
<input
name="mobile"
type="number"
className="form-control"
placeholder="Mobile No."
aria-label="Mobile No."
aria-describedby="button-addon2"
value={this.state.mobile}
onChange={this.handleInputChange}
/>
</div>
</div>
<div className="modal-footer">
<br />
<br />
<button
type="button"
className="btn btn-secondary"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
className="btn btn-primary"
data-dismiss="modal"
onClick={this.createUser}
>
Save
</button>
</div>
</div>
</div>
</div>
);
}
}
export default AddUser;
Action
import dispatcher from "../dispatcher/dispatcher";
import { BASE_URL } from "../utils/AppConstants";
export function getUsersList() {
console.log("getting the data! ");
fetch(BASE_URL + "/users")
.then(res => res.json())
.then(
result => {
console.log("res " + result);
dispatcher.dispatch({ type: "RECEIVE_USERS", users: result });
},
// Note: it's important to handle errors here instead of a catch() block so that
// we don't swallow exceptions from actual bugs in components.
error => {
// here manage error and close loading;
console.log("getting error " + error);
}
);
}
export function createNewUser(user) {
console.log("post the data!");
fetch(BASE_URL + "/saveuser", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(user)
})
.then(res => res.json())
.then(
result => {
dispatcher.dispatch({ type: "CREATE_USER", newUser: user });
},
// Note: it's important to handle errors here instead of a catch() block so that
// we don't swallow exceptions from actual bugs in components.
error => {
// here manage error and close loading;
console.log("getting error " + error);
}
);
}
Store
import { EventEmitter } from "events";
import dispatcher from "../dispatcher/dispatcher";
class UserStore extends EventEmitter {
constructor() {
super();
dispatcher.register(this.handleActions.bind(this));
this.users = [
{
branch: "19",
name: "Javcbvcsim11",
username: "zxcv",
mobile: "5645654",
email: "demo#gmail.com111",
address: "Demo vcbvcbAddress1",
dob: "2020-11-06T00:00:00.000+0000"
}
];
}
createUser(newUser) {
this.users.push(newUser);
console.log("new users lenght " + this.users.lenght);
this.emit("change");
}
getAll() {
return this.users;
}
handleActions(action) {
switch (action.type) {
case "RECEIVE_USERS": {
this.users = action.users;
this.emit("change");
break;
}
case "CREATE_USER": {
this.createUser(action.newUser);
break;
}
}
}
}
export default new UserStore();
I don't know what is the problem happened here.When checked in stack over flow i got that it's the problem of iterating the data. But i already did that. even though the error remain still.If any one can help it will be much appreciable.
The error thrown in setState method. i am here using flux as the architecture.The problem occures when i try to add a new user to my data.Actualyy when i add it inserting to db without any problem. the problem is when i click save button in my AddUser component it saves in to my db but after it need to show again as a table list but the error throws.
One problem which I can see is that you're using user.dob directly inside a JSX element (<td>{user.dob}</td>). dob is either new Date() or the direct output of react-datepicker's onChange event, both of which are objects.
Here's a dummy component which tried to render {new Date()}.
const App = ({ text }) => <p>{text}</p>;
// Passing Date object.
ReactDOM.render(<App text={new Date()} />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
This results in an error like this for me:
Objects are not valid as a React child (found: Mon Jan 21 2019 12:37:56 GMT+0530 (India Standard Time)).
Which means you're passing an object, not a string as a child to a JSX element.
Notice how this works:
const App = ({ text }) => <p>{text}</p>;
// Passing stringified Date object.
ReactDOM.render(<App text={new Date().toString()} />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
I pass a string as the child of the p JSX element. You need to do something similar and make sure no objects are passed.
Actually, since you didn't post your entire error, it's hard to say which entry is causing the error. But, user.dob is my best guess.
Iterating through objects is tricky in React. Generally you want to use Object.entries/Object.values/Object.keys and then .map. This takes the object and creates an array and then you can iterate through the object with .map. .map will not work on an object because it is an array function, so you have to turn your object into an array first. The .map function will allow you to iterate in React without that error:
this.state = {
branch: "",
name: "",
username: "",
mobile: "",
email: "",
address: ""
}
// Not in your constructor
let myObj = this.state;
Object.entries(myObj).map(item => {
// Successfully iterates, do what you need to do in here
})
Also, it's a very bad idea to use JQuery with React. React uses a virtual DOM and doesn't play well with JQuery.

React form will only update firstestore document when all inputs have been changed

My react form for updating profile data currently only interacts with firestore when all inputs have been changed.
Current Error;
TypeError: Cannot read property '0' of undefined" # profileActions.js:10:4
Things I have tried checked;
- Props dispatching to 'updateProfile' function - working
- Changing 'onChange' function to 'onSubmit' - didn't work
- Adding required to all input fields - didn't work
- Replacing defaultValue with placeholder - didn't work
Profile.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { updateProfile } from "../../actions/profileActions";
import Password from "./Password";
import { Redirect } from "react-router-dom";
class Profile extends Component {
state = {
firstName: this.props.profile.firstName,
lastName: this.props.profile.lastName,
businessName: this.props.profile.businessName,
phoneNumber: this.props.profile.phoneNumber,
email: this.props.profile.email
};
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
handleSubmit = e => {
e.preventDefault();
//console.log.apply(this.state);
this.props.updateProfile(this.state);
};
render() {
const { profile, profileError, auth } = this.props;
if (!auth.uid) return <Redirect to="/signin" />;
return (
<div className="container-fluid">
<form className="m-4" onSubmit={this.handleSubmit} to="/profile">
<div>{/* FIX - red line appears when bg-white removed below */}</div>
<div>
{/* FIX - form only submits correctly when all inputs have been changed */}
</div>
<div
className="alert-danger rounded col-xs-6 col-sm-6 col-md-6 col-lg-6 mx-auto bg-white"
style={{ color: "#ff0000" }}
>
{profileError ? <p>{profileError}</p> : null}
</div>
<div className="row">
<div className="col-xs-1 col-sm-1 col-md-1 col-lg-1" />
<div className="col-xs-3 col-sm-3 col-md-3 col-lg-3 d-flex flex-column mx-auto">
<div className="col-stretch rig-bot profile-label">
<h5 className="">First name :</h5>
</div>
<br />
<div className="col-stretch rig-bot profile-label">
<h5 className="">Last name :</h5>
</div>
<br />
<div className="col-stretch rig-bot profile-label">
<h5 className="">Business name :</h5>
</div>
<br />
<div className="col-stretch rig-bot profile-label">
<h5 className="">Phone number :</h5>
</div>
<br />
<div className="col-stretch rig-bot profile-label">
<h5 className="">Email :</h5>
</div>
<br />
</div>
<div className="col-xs-5 col-sm-5 col-md-5 col-lg-5 d-flex flex-column">
<div className="form-label-group">
<input
type="text"
id="firstName"
className="form-control"
defaultValue={profile.firstName}
autoFocus
onChange={this.handleChange}
/>
</div>
<br />
<div className="form-label-group">
<input
type="text"
id="lastName"
className="form-control"
defaultValue={profile.lastName}
onChange={this.handleChange}
/>
</div>
<br />
<div className="form-label-group">
<input
type="text"
id="businessName"
className="form-control"
defaultValue={profile.businessName}
onChange={this.handleChange}
/>
</div>
<br />
<div className="form-label-group">
<input
type="tel"
id="phoneNumber"
className="form-control"
defaultValue={profile.phoneNumber}
onChange={this.handleChange}
/>
</div>
<br />
<div className="form-label-group">
<input
type="email"
id="email"
className="form-control"
defaultValue={profile.email}
onChange={this.handleChange}
/>
</div>
<br />
</div>
<div className="col-xs-3 col-sm-3 col-md-3 col-lg-3" />
</div>
<div className="row">
<div className="col-xs-4 col-sm-4 col-md-4 col-lg-4 p-4 cen-mid mx-auto">
<input
className="btn btn-lg btn-primary btn-md"
type="submit"
value="Submit"
/>
</div>
</div>
</form>
<Password />
<div className="y-100" />
</div>
);
}
}
const mapStateToProps = state => {
console.log(state);
return {
profile: state.firebase.profile,
profileError: state.profile.profileError,
auth: state.firebase.auth
};
};
const mapDispatchToProps = dispatch => {
return {
updateProfile: profile => dispatch(updateProfile(profile))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Profile);
profileActions.js
export const updateProfile = props => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
const firestore = getFirestore();
const userId = getState().firebase.auth.uid;
const firstName = props.firstName;
const lastName = props.lastName;
const initials = props.firstName[0] + props.lastName[0];
const businessName = props.businessName;
const phoneNumber = props.phoneNumber;
const email = props.email;
firestore
.collection("users")
.doc(userId)
.update({
firstName: firstName,
lastName: lastName,
initials: initials,
businessName: businessName,
phoneNumber: phoneNumber,
email: email
})
.then(
firestore.collection("auditProfile").add({
userId: userId,
action: "update",
firstName: firstName,
lastName: lastName,
businessName: businessName,
phoneNumber: phoneNumber,
email: email,
changedOn: new Date()
})
)
.then(() => {
dispatch({ type: "UPDATE_PROFILE" });
})
.catch(err => {
dispatch({ type: "UPDATE_PROFILE_ERROR", err });
});
};
};
I currently have no rules attached to my firestore database and am really hoping the solution is something super stupid like; "firestore won't allow you to use update function if fieldValues are identical".
My brain has currently turned to mush so have given up. Please help?
Thanks in advance for anyone who gives this any time :)
One thing to point out is that you're setting the values in state in your onChange, but then never using those values in your inputs - you get defaultValue from props, but never assign value={this.state.profile.firstName} etc.
The error you're seeing points to props.firstName or props.lastName in profileActions.js being null/undefined (trying to access the 0th index on null/undefined will throw a TypeError). Are you setting initial values for those anywhere?
I'd suggest getting value for each of your inputs from state, and make sure you have initial data for first and last names.

Categories