Reputation: 1588
I have a react modal, which has a group of checkboxes. Those checkboxes "checked" value comes from an API call. But the problem is, that they only get updated on the second click.
I have tried to set a condition to wait for the fetch of the data before loading the group of checkboxes. So mi app looks like this
In my parent component where I load my data
I have set a permUpdated state, which equals to false, but once the data is loaded, i set it to true
getPermissionsValue() {
API.get('/user/' + this.state.rowId + '/permission')
.then(response => {
this.setState({
permissionValue: response.data,
permUpdated: true
}, () => {
// console.log(this.state.permissionValue)
});
})
}
That state is passed as a prop to the child component which is the modal
<EditUserModal permUpdated={this.state.permUpdated} ....>
And in the childs render, I used to have this, and it worked properly but with doesnt get updated
<div className="checkboxesIn">
{permissionsPrint}
</div>
{permissionsPrint}
are the checkboxes that I want to render. So ive set it like:
<div className="checkboxesIn">
{this.props.permUpdated ? {permissionsPrint} : null}
</div>
But that way my app crashes.
× Error: Objects are not valid as a React child (found: object with keys {permissionsPrint}). If you meant to render a collection of children, use an array instead.
This is how permissionPrint looks
(5) [{…}, {…}, {…}, {…}, {…}]
0: {$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}
1: {$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}
2: {$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}
3: {$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}
4: {$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}
length: 5
__proto__: Array(0)
This is how i create it
var permissionsPrint = [];
var valuesData = []
this.props.permissionValue.map(e => valuesData = Object.entries(e))
console.log(valuesData)
for (let i = 1; i < valuesData.length; i++) {
//console.log(valuesData[i][0]) //name of the permission
//console.log(valuesData[i][1]) //true false
permissionsPrint.push(<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id={valuesData[i][0]} value={valuesData[i][1]} defaultChecked={valuesData[i][1]} onChange={this.props.handleChangePermissions} />
<label class="form-check-label" for={"inlineCheckbox" + i} style={{ textTransform: "capitalize" }}>{valuesData[i][0]}</label>
</div>)
EDIT: Whole code of the modal
class EditUserModal extends React.Component {
constructor(props) {
super(props);
this.state = {
userId: ""
};
console.log("PROOPPSS");
console.log(props);
console.log(this.props.permUpdated);
}
componentDidUpdate() {}
componentDidMount() {
this.setState({
email: this.props.email
});
}
render() {
var permissionsPrint = [];
var valuesData = [];
this.props.permissionValue.map(e => (valuesData = Object.entries(e)));
console.log(valuesData);
for (let i = 1; i < valuesData.length; i++) {
//console.log(valuesData[i][0]) //name of the permission
//console.log(valuesData[i][1]) //true false
permissionsPrint.push(
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="checkbox"
id={valuesData[i][0]}
value={valuesData[i][1]}
defaultChecked={valuesData[i][1]}
onChange={this.props.handleChangePermissions}
/>
<label
class="form-check-label"
for={"inlineCheckbox" + i}
style={{ textTransform: "capitalize" }}
>
{valuesData[i][0]}
</label>
</div>
);
}
console.log("this is THE PROP OF PERMUPDATED");
console.log(this.props.permUpdated);
if (!this.props.show) {
return null;
}
return (
<div className="modalBg">
<div className="flex-container">
<div id="open-modal" className="modal-window">
<form onSubmit={this.props.handleSubmit}>
<div>
{/* <p>{this.props.userId}</p> */}
<FontAwesomeIcon
className="closeIcon"
onClick={this.props.close}
icon={faTimesCircle}
/>
<br></br>
{this.props.userDataUpdated ? (
<Alert
className="alertEditUser"
variant="success"
dismissible
onClose={this.props.handleDismiss}
>
User Data Updated
</Alert>
) : null}
{this.props.passwordMatchFailure ? (
<Alert
className="alertEditUser"
variant="danger"
dismissible
onClose={this.props.handleDismiss}
>
Passwords do not match
</Alert>
) : null}
{this.props.emailCantBeBlank ? (
<Alert
className="alertEditUser"
variant="danger"
dismissible
onClose={this.props.handleDismiss}
>
Email Cant Be Blank
</Alert>
) : null}
<div class="form-group emailgroup">
<label for="exampleFormControlInput1">
Change Email Address
</label>
<input
type="email"
class="form-control"
placeholder="[email protected]"
value={this.props.email}
onChange={this.props.handleChangeMail}
/>
</div>
{/* <div class="form-group emailgroup">
<label for="exampleFormControlInput1">Old Password</label>
<input type="password" class="form-control" />
</div> */}
<div class="form-group emailgroup">
<label for="exampleFormControlInput1">New Password</label>
<input
type="password"
class="form-control"
placeholder="Input new password"
onChange={this.props.handleChangePass}
/>
<input
type="password"
class="form-control"
placeholder="Confirm new password"
onChange={this.props.handleChangePass2}
style={{ marginTop: "5px" }}
/>
</div>
<div class="form-group emailgroup">
<label for="exampleFormControlInput1">User Permissions</label>
<br></br>
<div className="checkboxes">
<div className="checkboxesIn">
{/* {permissionsPrint} */}
{this.props.permUpdated ? permissionsPrint : null}
</div>
</div>
</div>
<div class="text-center">
<button class="btn btn-primary " type="submit">
Update
</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
export default EditUserModal;
Whole code of the admin
import React, { Component } from "react";
import API from "../services/axiosObject.js";
import "./css/Admin.css";
import Reactable from "reactable";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit } from "@fortawesome/free-regular-svg-icons";
import EditUserModal from "./EditUserModal";
export default class Admin extends Component {
constructor(props) {
super(props);
this.state = {
retracted: false,
userList: [],
showModal: false,
rowId: "",
selectedMail: "",
password: "",
password2: "",
userDataUpdated: false,
passwordMatchFailure: false,
emailCantBeBlank: false,
permissionValue: [],
permUpdated: false
};
this.getUserList = this.getUserList.bind(this);
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.handleChangeMail = this.handleChangeMail.bind(this);
this.handleChangePass = this.handleChangePass.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleDismiss = this.handleDismiss.bind(this);
this.handleChangePermissions = this.handleChangePermissions.bind(this);
this.getPermissionsValue = this.getPermissionsValue.bind(this);
}
componentDidUpdate() {}
componentDidMount() {
this.getUserList();
}
handleChangeMail = evt => {
this.setState({
selectedMail: evt.target.value
});
};
handleChangePass = evt => {
this.setState({
password: evt.target.value
});
};
handleChangePass2 = evt => {
this.setState({
password2: evt.target.value
});
};
handleChangePermissions = evt => {
console.log(this.state.permissionValue);
console.log("id: " + evt.target.id);
var idu = evt.target.id;
var checked = evt.target.checked;
console.log("checked: " + evt.target.checked);
var data = this.state.permissionValue[0];
console.log("data1");
console.log(data);
data[idu] = checked;
console.log("data2");
console.log(data);
this.setState({
permissionValue: [data]
});
};
getUserList() {
API.get("/userlist").then(response => {
this.setState(
{
userList: response.data
},
() => {
console.log(this.state.userList);
}
);
});
}
handleSubmit(event) {
event.preventDefault();
//console.log("updating")
//console.log("email: " + this.state.selectedMail)
var email = this.state.selectedMail;
var password = this.state.password;
var password2 = this.state.password2;
var permissionValue = this.state.permissionValue;
console.log("....");
console.log("password: " + this.state.password);
console.log("password2: " + this.state.password2);
console.log("....");
console.log("userId: " + this.state.rowId);
console.log("email: " + email);
if (password2 != password || email == "") {
console.log("P2: " + password2);
console.log("P1: " + password);
if (password2 != password) {
console.log("CONTRASEÑAS DISTINTAS");
this.setState({
passwordMatchFailure: true
});
} else {
this.setState({
emailCantBeBlank: true
});
}
} else {
console.log("ENTRA EN EL ELSE");
if (password == undefined || password2 == undefined) {
password = "";
password2 = "";
}
API.post("/user/update/" + this.state.rowId, {
email,
password,
permissionValue
}).then(response => {
console.log(permissionValue);
if (response.data == "user data updated") {
this.setState(
{
userDataUpdated: true
},
() => {
console.log(this.state.userDataUpdated);
}
);
}
});
}
}
handleDismiss() {
console.log("HANDLING DISMISSSSSSSSSSSSSSSSS");
this.setState({
userDataUpdated: false,
passwordMatchFailure: false,
emailCantBeBlank: false
});
}
showModal(rowId, rowEmail) {
this.setState(
{
showModal: true,
rowId: rowId,
selectedMail: rowEmail
},
() => {
this.getPermissionsValue();
}
);
}
closeModal() {
console.log("CLOOOOOOSSSSINNGGGGGGGGGGGGG");
this.setState(
{
showModal: false
},
() => {
// console.log("clicked closeModal")
// console.log(this.state.showModal)
}
);
}
getPermissionsValue() {
API.get("/user/" + this.state.rowId + "/permission").then(response => {
this.setState(
{
permissionValue: response.data,
permUpdated: true
},
() => {}
);
});
}
render() {
var users = this.state.userList;
const Table = Reactable.Table,
Td = Reactable.Td,
Tr = Reactable.Tr;
if (users.length === 0) {
return <p>loading</p>;
}
return (
<div class="maincontainer">
<div className="content-landing">
<button
class="btn btn-primary "
style={{ float: "right", marginRight: "20px" }}
onClick={() => this.props.history.push("/register")}
>
New user
</button>
<Table
className="table"
filterable={["Email"]}
itemsPerPage={8}
currentPage={0}
sortable={true}
>
{users.map(row => {
return (
<Tr className={row.className}>
<Td column="Email">{row.email}</Td>
<Td column="Edit">
<FontAwesomeIcon
className="editIcon"
onClick={() => this.showModal(row.id, row.email)}
icon={faEdit}
/>
</Td>
</Tr>
);
})}
</Table>
<EditUserModal
permUpdated={this.state.permUpdated}
permissionValue={this.state.permissionValue}
emailCantBeBlank={this.state.emailCantBeBlank}
userDataUpdated={this.state.userDataUpdated}
handleChangePermissions={this.handleChangePermissions}
passwordMatchFailure={this.state.passwordMatchFailure}
handleDismiss={this.handleDismiss}
show={this.state.showModal}
close={this.closeModal}
userId={this.state.rowId}
email={this.state.selectedMail}
handleChangePass={this.handleChangePass}
handleChangePass2={this.handleChangePass2}
handleChangeMail={this.handleChangeMail}
handleSubmit={this.handleSubmit}
/>
</div>
</div>
);
}
}
Upvotes: 1
Views: 1435
Reputation: 1588
Se issue was that when the modal was closed, permUpdated state was kept as true, so I had to set it to false on close
closeModal() {
console.log("CLOOOOOOSSSSINNGGGGGGGGGGGGG")
this.setState({
showModal: false,
permUpdated: false
}, () => {
// console.log("clicked closeModal")
// console.log(this.state.showModal)
});
}
Upvotes: 0
Reputation: 1508
Here {this.props.permUpdated ? {permissionsPrint} : null}
I don't think you need curly braces around permissionsPrint
it should be :
{this.props.permUpdated ? permissionsPrint : null}
{permissionsPrint}
this is the same as {permissionsPrint: permissionsPrint}
which is an Object with same key and value names, where value is a variable of the same name as of key name.
Upvotes: 2