Row click react.js - javascript

this component react presents a table with its own row id, what I want to do is to have the possibility to select the row with the mouse-click at the user's click, how can I implement this within this react application? The table loads a series of values โ€‹โ€‹from the backend which then displays with reactstrap, how can I fix this?
React.js Code:
class Static extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
this.state = {
tableStyles: [
],
};
this.checkAll = this.checkAll.bind(this);
}
parseDate(date) {
this.dateSet = date.toDateString().split(" ");
return `${date.toLocaleString("en-us", { month: "long" })} ${
this.dateSet[2]
}, ${this.dateSet[3]}`;
}
checkAll(ev, checkbox) {
const checkboxArr = new Array(this.state[checkbox].length).fill(
ev.target.checked
);
this.setState({
[checkbox]: checkboxArr,
});
}
//Function create user
async newuser(event){
let ragionesocialetext = event.target.value;
console.log("Ragione Sociale: "+ragionesocialetext);
}
//Function call con text change
async handleChange(event) {
let searchtext = event.target.value;
var result=await ricercaclienti(searchtext);
var results=[];
for(var i=0; i<result.length; i++){
var value={
id: result[i].IdCliente,
picture: require("../../../images/cliente.jpg"), // eslint-disable-line global-require
description: result[i].RagioneSociale,
info: {
citta: result[i].Citta,
provincia: result[i].Provincia,
},
DataInserimento: result[i].DataInserimento,
Cap: result[i].Cap,
progress: {
percent: 30,
colorClass: "warning",
}
};
results.push(value);
}
this.setState({tableStyles: results});
}
render() {
return (
<div className={s.root}>
<h2 className="page-title">
Clienti - <span className="fw-semi-bold"> Anagrafia</span>
</h2>
<Row>
<Col>
<Widget
settings
close
bodyClass={s.mainTableWidget}
>
<p></p>
<p></p>
<p></p>
<p></p>
<FormGroup >
<InputGroup className="input-group-no-border">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="fa fa-search text-white" />
</InputGroupText>
</InputGroupAddon>
<Input
id="search-input"
className="input-transparent"
placeholder="Ricerca"
type='text'
name='ricerca'
onChange={this.handleChange.bind(this)}
/>
</InputGroup>
</FormGroup>
<Table striped>
<thead>
<tr className="fs-sm">
<th className="hidden-sm-down">#</th>
<th>Cliente</th>
<th>Ragione Sociale</th>
<th className="hidden-sm-down">Indirizzo</th>
<th className="hidden-sm-down">Data Inserimento</th>
<th className="hidden-sm-down">CAP</th>
<th className="hidden-sm-down">Stato</th>
</tr>
</thead>
<tbody>
{this.state.tableStyles.map((row) => (
<tr key={row.id}>
<td>{row.id}</td>
<td>
<img
className="img-rounded"
src={row.picture}
alt=""
height="50"
/>
</td>
<td>
{row.description}
{row.label && (
<div>
<Badge color={row.label.colorClass}>
{row.label.text}
</Badge>
</div>
)}
</td>
<td>
<p className="mb-0">
<small>
Cittร :
<span className="text-muted fw-semi-bold">
{row.info.citta}
</span>
</small>
</p>
<p>
<small>
Provincia:
<span className="text-muted fw-semi-bold">
{row.info.provincia}
</span>
</small>
</p>
</td>
<td className="text-muted">{row.DataInserimento}</td>
<td className="text-muted">{row.Cap}</td>
<td className="width-150">
<Progress
color={row.progress.colorClass}
value={row.progress.percent+row.i}
className="progress-sm mb-xs"
/>
</td>
</tr>
))}
</tbody>
</Table>
<div className="clearfix">
<div className="float-right">
<Button color="default" className="mr-2" size="sm">
Refresh...
</Button>
<UncontrolledButtonDropdown>
<DropdownToggle
color="inverse"
className="mr-xs"
size="sm"
caret
>
Nuovo Cliente
</DropdownToggle>
<DropdownMenu>
<DropdownItem>Inserisci ragione sociale</DropdownItem>
<Input
id="search-input"
className="input-transparent"
placeholder="ragionesociale"
type='text'
name='ragionesociale'
onChange={this.newuser.bind(this)}
/>
</DropdownMenu>
</UncontrolledButtonDropdown>
</div>
<p></p>
</div>
</Widget>
</Col>
</Row>
</div>
);
}
}

You should set a selectedRowId variable in your state, then add
onClick={() => {this.setState({ selectedRowId: row.id })}}
prop to wherever the user should click to select the row. If you want to change the styles of the row based on if it is selected or not, you can change the class of the row element by adding
className={this.state.selectedRowId===row.id?'selected':'unselected'}
then adding styles for a selected and unselected class.

Related

Displaying multiple PDF files in reactjs

I am new to react and I have multiple pdfs that I am trying to display depending on the link selected. I have managed to display a PDF from a selectable list of links of my PDFs stored inside the src directory. However, the same pdf appears for all the links. When I try to display different pdfs, I get this error:
.
For PDF viewing I used the code from here:
https://npm.io/package/react-pdf
My question is how can I implement such a case where I can display a different pdf depending on the link I would have clicked.
My code to display the pdf depending on the link looks like this:
import React, { Component, useState } from "react";
import { Document, Page } from "react-pdf";
import myPdf from '../../../components/pdf/signed.pdf'
import ViewPdf from '../../../components/ViewPdf'
import ViewSecondPdf from '../../../components/ViewPdf2'
import ViewThirdPdf from '../../../components/ViewPdf3'
import AllPages from "src/components/pdf/AllPages";
import { Table, Col, Row, Button } from 'reactstrap'
import { Link } from "react-router-dom";
const Display = (props) => {
<div>
<AllPages pdf={props} />
</div>
}
const DocTable = ({ onToggle }) => {
return (
<>
<Link to="/sign" className="mb-2"><span className="material-icons">keyboard_backspace</span></Link><br />
<span style={{ fontWeight: 'bold' }}>Documents</span><br />
<Table bordered hover size="sm">
<thead>
<br />
<tr>
<th>ID</th>
<th>Document Name</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">001</th>
<td><Button id="MICButton" name="MICButton" color="link" onClick={onToggle}>Vehicle Insurance Claim</Button></td>
<td>Signed</td>
</tr>
<tr>
<th scope="row">002</th>
<td><Button id="HIButton" name="HIButton" color="link" onClick={onToggle}>Household Insurance Contract</Button></td>
<td>Signed</td>
</tr>
<tr>
<th scope="row">003</th>
<td><Button id="CIButton" name="CIButton" color="link" onClick={onToggle}>Vehicle Insurance Contract</Button></td>
<td>Not Signed</td>
</tr>
</tbody>
</Table>
<br />
</>
);
}
const DocumentList = () => {
const [isVisible, setIsVisible] = useState(false) // false to hide the PDF for the first time
const handleToggle = () => {
setIsVisible(prevState => !prevState)
}
if(document.getElementById('MICButton').onToggle == true){
return (
<div>
<Row>
<Col xs="6">
<DocTable isVisible={isVisible} onToggle={handleToggle} />
</Col>
<Col xs="6">
{isVisible && <ViewPdf />}
</Col>
</Row>
</div>
);
}
if(document.getElementById('HIButton').onToggle == true){
return (
<div>
<Row>
<Col xs="6">
<DocTable isVisible={isVisible} onToggle={handleToggle} />
</Col>
<Col xs="6">
{isVisible && <ViewSecondPdf />}
</Col>
</Row>
</div>
);
}
if(document.getElementById('CIButton').onToggle == true){
return (
<div>
<Row>
<Col xs="6">
<DocTable isVisible={isVisible} onToggle={handleToggle} />
</Col>
<Col xs="6">
{isVisible && <ViewThirdPdf />}
</Col>
</Row>
</div>
);
}
}
export default DocumentList
You could pass the PDF ID to the onToggle and then, depending on it, display the required component
const DocTable = ({ onToggle }) => {
return (
<>
<Link to="/sign" className="mb-2">
<span className="material-icons">keyboard_backspace</span>
</Link>
<br />
<span style={{ fontWeight: 'bold' }}>Documents</span>
<br />
<Table bordered hover size="sm">
<thead>
<br />
<tr>
<th>ID</th>
<th>Document Name</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">001</th>
<td>
<Button id="MICButton" name="MICButton" color="link" onClick={() => onToggle('MICButton')}>
Vehicle Insurance Claim
</Button>
</td>
<td>Signed</td>
</tr>
<tr>
<th scope="row">002</th>
<td>
<Button id="HIButton" name="HIButton" color="link" onClick={() => onToggle('HIButton')}>
Household Insurance Contract
</Button>
</td>
<td>Signed</td>
</tr>
<tr>
<th scope="row">003</th>
<td>
<Button id="CIButton" name="CIButton" color="link" onClick={() => onToggle('CIButton')}>
Vehicle Insurance Contract
</Button>
</td>
<td>Not Signed</td>
</tr>
</tbody>
</Table>
<br />
</>
);
};
const DocumentList = () => {
const [isVisible, setIsVisible] = useState(false); // false to hide the PDF for the first time
const [activeDoc, setActiveDoc] = useState(null);
const handleToggle = (docID) => {
setIsVisible((prevState) => !prevState);
setActiveDoc(docID);
};
return (
<div>
<Row>
<Col xs="6">
<DocTable isVisible={isVisible} onToggle={handleToggle} />
</Col>
<Col xs="6">
{(() => {
if(!isVisible){
return null
}
switch (activeDoc) {
case 'MICButton':
return <ViewPdf />;
case 'HIButton':
return <ViewSecondPdf />;
case 'CIButton':
return <ViewThirdPdf />;
default:
return null;
}
})()}
</Col>
</Row>
</div>
);
};

Mapping through data in my state and creating new rows in my table

Currently I have a table that I'm trying to insert additional rows into after mapping through some data. There is 6 table-headers so naturally the data is divided up into 6 "table-data" sections. I'm trying to map through and create a new row for each object in the array of data. The data shows up in a new row as wanted, however, it is all placed in the first table-data section of that row. Please see code below.
**This is where I'm mapping through the data:
<div id="logs">
<div className="container">
<table className="highlight">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Attention</th>
<th>Due In:</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{logs !== null && !loading ? (
<TransitionGroup>
{filtered !== null
? filtered.map((log) => (
<CSSTransition
key={log._id}
timeout={300}
classNames="item"
>
<LogItem log={log} />
</CSSTransition>
))
: logs.map((log) => (
<CSSTransition
key={log._id}
timeout={300}
classNames="item"
>
<LogItem log={log} />
</CSSTransition>
))}
</TransitionGroup>
) : (
<Loader />
)}
</tbody>
</table>
<div className="fixed-action-btn">
<a
href="#add-log-modal"
className="btn-floating pulse btn-large green darken-2 modal-trigger tooltipped"
data-tooltip="Open New Issue"
data-position="left"
>
<i className="large material-icons">add</i>
</a>
</div>
</div>
</div>
**This is where I'm creating the new table row:
const { deleteLog, setCurrent } = logContext;
const { _id, title, attention, date, description, due } = log;
const onDelete = () => {
deleteLog(_id);
M.toast({ html: "Log item has been removed" });
};
var dueDate = moment(due, "MMM DD, YYYY").fromNow(true);
return (
<div>
<tr>
<td>{title}</td>
<td className="truncated">{description}</td>
<td>
{" "}
<i
className={`material-icons action ${
attention === "Needs Attention" ? "red-text" : "green-text"
}`}
>
{`${
attention === "Needs Attention"
? "do_not_disturb_alt"
: "done_all"
}`}
</i>
</td>
<td>
<span
className={`due-date ${
dueDate <= "3"
? "green lighten-2"
: dueDate <= "6"
? "amber lighten-2"
: "red darken-1"
}`}
>
<p>Due in {dueDate}</p>
</span>
</td>
<td>
<a
href="#edit-log-modal"
className="modal-trigger"
onClick={() => setCurrent(log)}
>
<i className="material-icons small card-link amber-text text-accent-2">
edit
</i>
</a>
</td>
<td>
{" "}
<a href="#!" onClick={onDelete} className="">
<i className="material-icons small white-text card-link">delete</i>
</a>
</td>
</tr>
</div>
);

Changing variable in one file conflicts the data for other file in React JS

I'm having weird problem in React JS. I have two classes named as Notes.js and DataTables.js
I'm using DataTables in Note.js like this
<DataTables
keyField="id"
columns={columns}
url={this.state.url}
useCallBack={true}
onEdit={this.onEdit}
/>
Please Note that DataTables.js is my own custom created DataTable.js not react-datatable.
All the work like fetching data from URL and showing it in tabular form is in DataTables.js file.
Note.js Code:
import React, { Component } from "react";
import { Constant } from "../shared/Constants";
import DataTables from "../shared/DataTables";
import { Modal, Button } from "react-bootstrap";
import BreadCrumb from "../shared/BreadCrumb";
import "../Style.css";
const columns = Constant.notes;
export class Notes extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
url: "notes/get_notes",
showModal: false,
note: [],
};
this.onEdit = this.onEdit.bind(this);
this.onAdd = this.onAdd.bind(this);
this.onUpdate = this.onUpdate.bind(this);
this.saveNote = this.saveNote.bind(this);
}
onUpdate(key, value) {
let noteData = this.state.note;
noteData[key] = value;
this.setState({
note: noteData,
});
}
saveNote(e) {
e.preventDefault();
}
onEdit(n) {
this.setState({
note: n,
showModal: true,
});
}
onAdd() {
this.setState({
note: [],
showModal: true,
});
}
render() {
return (
<>
<Modal
show={this.state.showModal}
aria-labelledby="example-modal-sizes-title-lg"
onHide={() => this.setState({ showModal: false })}
>
<form method="post" onSubmit={this.saveNote}>
<Modal.Header>
<Modal.Title>My Note</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="row">
<div className="col-sm-12">
<div className="form-group">
<label className="text-muted">Note Title</label>
<input
type="text"
placeholder="Note Title"
className="form-control"
ref="title"
value={this.state.note.title}
onChange={(e) => this.onUpdate("title", e.target.value)}
/>
</div>
<div className="form-group">
<label className="text-muted">Content</label>
<textarea
onChange={(e) => this.onUpdate("content", e.target.value)}
className="form-control"
style={{ height: "250px" }}
placeholder="Content"
>
{this.state.note.content}
</textarea>
</div>
</div>
</div>
</Modal.Body>
<Modal.Footer>
<Button
variant="secondary"
onClick={() => this.setState({ showModal: false })}
>
Close
</Button>
<Button type="submit" variant="primary">
Save Note
</Button>
</Modal.Footer>
</form>
</Modal>
<BreadCrumb
title="My Notes"
useCallBack={true}
onAdd={this.onAdd}
active_link="Notes"
link=""
link_text="Add New"
/>
<div className="row">
<div className="col-sm-12">
<div className="card">
<div className="card-body">
<div className="card-title">Notes</div>
<DataTables
keyField="id"
columns={columns}
url={this.state.url}
useCallBack={true}
onEdit={this.onEdit}
/>
</div>
</div>
</div>
</div>
</>
);
}
}
export default Notes;
I'm having Problem in Note.js on onUpdate function
onUpdate(key, value) {
let noteData = this.state.note;
noteData[key] = value;
this.setState({
note: noteData,
});
}
Problem: When I update a field in Modal as you can see in my code, then my Table in DataTable.js automatically gets updated, I'don't why :/
Here is DataTables.js function where I'm sending data to onEdit function
const TableData = () => {
return (
<tbody>
{tableData.length === 0 ?
<tr>
<td className="text-center" colSpan="5"><strong>No Data Found</strong></td>
</tr>
:
tableData.map((tData) => (
<tr key={tData[this.props.keyField]}>
{this.props.columns.map((item, index) => (
<td key={index} className="table-content">
{index === 0 ?
[(useCallback === true ? <span key={"sub_"+index} className="link" onClick={() => this.props.onEdit(tData)}>{tData[item.dataField]}</span> :
<Link
to={
this.props.edit_link +
"/" +
tData[this.props.edit_key_first] + (this.props.edit_key_second ? "/" +
tData[this.props.edit_key_second] : '')
}
>
{tData[item.dataField]}
</Link>
)]
: (
tData[item.dataField]
)}
</td>
))}
</tr>
))}
</tbody>
);
};
Please check gif image below so you can understand it :P
You have an onChange function that is updating the content
onChange={(e) => this.onUpdate("content", e.target.value)}
If you don't want to change the content while typing then you will have to remove this.

Checking all value from a json object to render the view

I'm pretty new to reactjs and I came to a situation where I cannot solved !
My app has a json array in this following format:
[
{"email":"sample1#sample.com", "mobile":"000000", "iscompleted":"false"},
{"email":"sample2#sample.com", "mobile":"000000", "iscompleted":"false"},
{"email":"sample3#sample.com", "mobile":"000000", "iscompleted":"false"},
{"email":"sample4#sample.com", "mobile":"000000", "iscompleted":"false"}
]
In my app logic, once I send a POST request and get its return response I update the iscompleted to True.
Then, I have a click button that refresh the application to its original state... however, I want to only display the button if all items in the json object is as "iscompleted":"true".
The question here, is how is the best approach to do that ?
I'm using react hooks for all my code, although, i dont know if its relevant.
I was thinking in a arrow function that returns true then i can use the following:
{is_all_completed ? <StartAgainBtn /> : null}
Thank you
Update
I'm using the following code logic at the end of the file. Also, I'm using const and arrow functions. As you can tell, I'm pretty new to react !
return (
<div>
{props.recipients[0] && !props.report_sent ? <UserRecipientsTableView /> : null}
{props.report_sent ? <ReportsSubmittedTable /> : null}
{props.report_sent? <StartAgainBtn /> : null}
{user_confirmed && !props.report_sent ? <SendReports /> : null}
</div>
);
};
export default Confirmation;
Update2
Full code controller goes below:
import React, { useState } from "react";
import axios from "axios";
import { toast } from "react-toastify";
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
import InputAdornment from "#material-ui/core/InputAdornment";
const Confirmation = props => {
const [user_confirmed, setUserInputConfirmation] = useState('');
const [recipients, updateRecipients] = useState(props.recipients);
const handleSubmit = e => {
e.preventDefault();
props.setReportSent(true)
props.recipients.forEach(function (element, index) {
// Make it spin !
updateRecipients([...recipients, element['iscomplete'] = false, element['errors'] = false])
axios
.post("/api/delivery/", element,
{
headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${props.accessToken}`
},
})
.then(function(response) {
if (response.status === 202){
updateRecipients([...recipients, element['iscomplete'] = true, element['errors'] = false])
// for (const [key, value] of Object.entries(response.data)) {
// toast.success(` ๐ŸŽ‰ ${key}: ${value} ๐ŸŽ‰`);
// }
}
})
.catch(function(error) {
toast.error(` ๐Ÿ˜ฅ Oh no! {${error.response.data}`);
console.log(error.response.data);
updateRecipients([...recipients, element['iscomplete'] = true, element['errors'] = true])
// updateReportSentList([...report_sent_list, {element}])
for (const [key, value] of Object.entries(error.response.data)) {
toast.error(` ๐Ÿ˜ฅ Oh no! ${key}: ${value}`);
}
});
});
};
const UserConfirmationView = () => {
if (user_confirmed)
return (
<div>
<br/>
<span>
<h4>Please go ahead and click 'SEND IT'!</h4>
</span>
<br></br>
</div>
)
else {
return(
<div className='user-consent-input'>
<br></br>
<TextField
id="input-with-icon-grid"
label=""
placeholder='If you agree to the above, please type CONFIRMED in here ...'
// variant="outlined"
onChange={handleUserConfirmation}
style = {{width: 500}}
error={!user_confirmed ? true : false}
// helperText={name.error ? name.helptext : ""}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<i className="fas fa-check-double"></i>
</InputAdornment>
)
}}
/>
<br></br>
</div>
)
}
}
const UserRecipientsTableView = () => {
return (
<div className="card">
<div className="card-body">
<p className="you-are-about"> You are about to send <span className="userconfirm-view-filename-attr"> {props.filename}</span> to these contacts
below as <spam className="userconfirm-view-filename-attr"> {props.project_owner_name}</spam> being the project owner of the jobID: <spam className="userconfirm-view-filename-attr">{props.project_id}</spam>.</p>
<br>
</br>
<p className="card-text">
<div className="recipients-table">
<table className="table table-hover table-sm">
<thead className='thead-dark'>
<tr>
<th scope="col">Recipient's Name </th>
<th scope="col">Recipient's Email</th>
<th scope="col">Recipient's Mobile</th>
<th scope="col">Project Desc</th>
<th scope="col"></th>
</tr>
</thead>
{/* Table body */}
{props.allRecipients}
</table>
</div>
<p>
<div className="userconfirm-view">
<br></br>
<p className="you-are-about"> If you agree, please type <span className="userconfirm-view-filename-attr">CONFIRMED</span> into the box below.</p>
<div className="col final-buttom" >
<UserConfirmationView />
</div>
</div>
</p>
</p>
</div>
</div>
);
};
const handleUserConfirmation = e => {
if (e.target.value.trim().toUpperCase() === "CONFIRMED") {
setUserInputConfirmation("Confirmed");
} else
setUserInputConfirmation("");
// setName({ error: true, helptext: "Wrong!" });
};
const SendReports = () => {
if(user_confirmed){
return (
<Button variant="contained" color="secondary"
onClick={handleSubmit}
fullWidth={true}
size="medium"
style={{fontSize: "59px"}}
// style={{minWidth: '300px', minHeight: '130px', marginTop: '40px', fontWeight: '700', lineHeight: '22px', marginBottom: '25px'}}
// startIcon={<i className="fas fa-file-upload fa-6x"></i>}
>
<h4 className="send-it">Send it!</h4>
</Button>
);
}else{
return (
alert("Can't submit it! Please start again.")
)
}
};
const statusStyle = (item) => {
if (!item['iscomplete'] && (!item['errors'])) {
// spin loader ...
return(<span><i className="fas fa-spinner fa-spin fa-2x"></i> Loading ...</span>)
} else if (item['iscomplete'] && (!item['errors'])) {
// if completed and no errros how Success
return(<Button
variant="contained"
color="secondary"
className='success-btn'
startIcon={<i className="fas fa-check-circle fa-2x"></i>}
>
DELIVERED!
</Button>)
// return (<span><i className="fas fa-check-circle fa-2x"></i>Delivered!</span>);
} else {
// Damn boy ! something went wrong!
return(<Button
classes={{ label: 'failed-button' }}
variant="contained"
color="secondary"
startIcon={<i className="fas fa-exclamation-triangle fa-2x"></i>}
>
Failed
</Button>)
// return (<span><i className="fas fa-exclamation-triangle fa-2x"></i>Please, try again ...</span>);
}
}
const ReportsSubmittedTable = () => {
const tableAfterReportSent = props.recipients.map((item, index) =>
<tbody key={index}>
<tr>
<th scope="row">{item.client_name}</th>
<td>{item.client_email}</td>
<td>{item.client_mobile}</td>
<td>{statusStyle(item)}</td>
{/* <td>{statusStyle(item.iscomplete)}</td> */}
{/* <td><i className="recipients-x-remove" onClick={() => removeTodo(index)}><span role='img'> โŒ </span></i></td> */}
</tr>
</tbody>
);
return (
<div className="card" onChange={ReportsSubmittedTable}>
<div className="card-body">
{/* <h5 className="card-title">I'm doing what you told me to ... Please, hold on!</h5> */}
<br></br>
{/* <h6 className="card-subtitle mb-2 text-muted">You are about to send <span>{props.filename}</span> to the following people: </h6> */}
<p className="card-text">
<div className="recipients-table">
<table className="table table-hover table-sm">
<thead className='thead-dark'>
<tr>
<th scope="col">Recipient's Name </th>
<th scope="col">Recipient's Email</th>
<th scope="col">Recipient's Mobile</th>
<th scope="col">Status</th>
{/* <th scope="col">Errors</th> */}
</tr>
</thead>
{/* Table body */}
{tableAfterReportSent}
</table>
</div>
<p>
<hr></hr>
</p>
</p>
</div>
</div>
);
};
const StartAgainBtn = () => {
if (props.report_sent){
return (
<div className="card completed">
<div className="card-body">
<div className="row">
<div className="col">
<h4>Completed!</h4>
<br></br>
<h4>Want to send a new file ?</h4>
</div>
<div className="col">
<Button
variant="outlined"
color="primary"
size="large"
onClick={e => props.resetfile()}
style={{
minWidth: "100%",
minHeight: "100%",
// marginTop: "20px",
fontWeight: "600",
// lineHeight: "22px"
}}
>
<i className="fas fa-redo fa-4x"></i>
<h4 className="start-again">{ }Start Again!</h4>
</Button>
</div>
</div>
</div>
</div>
);
}
}
return (
<div>
{props.recipients[0] && !props.report_sent ? <UserRecipientsTableView /> : null}
{props.report_sent ? <ReportsSubmittedTable /> : null}
{props.report_sent? <StartAgainBtn /> : null}
{user_confirmed && !props.report_sent ? <SendReports /> : null}
</div>
);
};
export default Confirmation;
You could do something like this:
Create a function that takes the list and checks for isComplete property of each item on the array.
Then you can just call that function on your ternary operator {isAllCompleted(JSON.parse(responseDataASJSON))? <StartAgainBtn /> : null}
// param ="resultData" is the data received from Ajax Response. data must be a javascript object.
function isAllCompleted(data){
for(let i =0; i < data.length; i++){
if(data[i].isCompleted === "false"){
// If any false value was found, return false
//
return false;
}
}
// At this point, no value was found to be false,
// because it wouldn't returned false based on the loop block
return true;
}
You can use the JS function .every() for easy iteration through the JSON object.
is_all_completed = YourJSONObj.every(function (n) { return n.iscompleted === "true";})
I hope it helps.
That ternary will work fine. I typically like to simplify it even more with the following:
{ is_all_completed && <StartAgainBtn /> }
Just makes things a little more concise but either way works.

ReactJS Modal component won't close onclick

I have created a user CRUD api that is linked to a reactJs front end. I have been using the bootstrap components and decied to use the modal component to have edit forms. The only issue is that for some reason when the modal opens, I can not exit it again unless I reload the browser.
The code for the EditUserModal.js is as follows:
import React, { Component } from 'react';
import {Modal, Button, Row, Col, Form} from 'react-bootstrap';
import * as moment from 'moment';
const BASE_API_URL = `http://localhost:56062/api/users`;
var currentDate = new Date();
export class EditUserModal extends Component{
constructor(props){
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount(){
}
handleSubmit(event){
event.preventDefault();
fetch(BASE_API_URL,{
method:'PUT',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
Id: event.target.Id.value,
firstName: event.target.firstName.value,
lastName: event.target.lastName.value,
Email: event.target.Email.value,
mobileNumber: event.target.mobileNumber.value,
dateOfBirth: event.target.dateOfBirth.value,
lastModified: currentDate
})
})
.then(res=> res.json())
.then((result) =>
{
console.log(result);
},
(error) => {
console.log('Failed')
}
)
}
render(){
return(
<Modal
{...this.props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Edit User
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="editFormContainer">
<Row>
<Col sm={12}>
<Form onSubmit={this.handleSubmit}>
<Form.Group controlId="Id">
<Form.Label>User ID</Form.Label>
<Form.Control name="Id" disabled defaultValue = {this.props.userid} type="text" placeholder="Id" />
</Form.Group>
<Form.Group controlId="firstName">
<Form.Label>First Name</Form.Label>
<Form.Control name="firstName" required type="text" defaultValue = {this.props.firstname} placeholder="First Name" />
</Form.Group>
<Form.Group controlId="lastName">
<Form.Label>Last Name</Form.Label>
<Form.Control name="lastName" required type="text" defaultValue = {this.props.lastname} placeholder="Last Name" />
</Form.Group>
<Form.Group controlId="Email">
<Form.Label>Email address</Form.Label>
<Form.Control name="Email" required type="email" defaultValue = {this.props.useremail} placeholder="Email e.g. name#example.com" />
</Form.Group>
<Form.Group controlId="mobileNumber">
<Form.Label>Mobile Number</Form.Label>
<Form.Control name="mobileNumber" required type="text" defaultValue = {this.props.mobilenumber} placeholder="Mobile e.g. 0723218223 or +447236475886" />
</Form.Group>
<Form.Group controlId="dateOfBirth">
<Form.Label>Date of Birth</Form.Label>
<Form.Control name="dateOfBirth" required type="date" defaultValue = {moment(new Date(this.props.dateofbirth)).format('YYYY-MM-DD')} placeholder="Date of Birth e.g. 05-02-97" />
</Form.Group>
<Form.Group>
<Button variant="primary" type="submit">Edit User</Button>
</Form.Group>
</Form>
</Col>
</Row>
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="danger" onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
)
}
}
And then for the page the modal is used, the code related is as follows:
export class User extends Component {
constructor(props){
super(props);
this.state = {users:[], addModalShow : false, editModalShow: false}
}
render(){
const {users, userid, firstname, lastname, useremail, mobilenumber, dateofbirth, lastmodified} = this.state;
let addModalClose =() => this.setState({addModalShow:false});
let editModalClose =() => this.setState({editModalShow:false});
return(
<div>
<ButtonToolbar>
<Button variant='outline-dark' style={{margin:"auto"}} onClick={()=> this.setState({addModalShow:true})}>
Add User
</Button>
<AddUserModal show={this.state.addModalShow} onHide={addModalClose} />
</ButtonToolbar>
<Table responsive borderless style={{borderRadius:"0.3em"}} striped hover size="sm" variant="dark" className="mt-4">
<thead>
<tr>
<th>Id</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Mobile Number</th>
<th>Date of Birth</th>
<th>Last Modified</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{users.map(user=>
<tr key = {user.Id}>
<td>{user.Id}</td>
<td>{user.firstName}</td>
<td>{user.lastName}</td>
<td>{user.Email}</td>
<td>{user.mobileNumber}</td>
<td>{moment(new Date(user.dateOfBirth)).format('YYYY-MM-DD')}</td>
<td>{user.lastModified}</td>
<td>
<ButtonToolbar>
<Button className="mr-2" variant="outline-light" onClick={()=> { ReactDOM.render(<EditUserModal show={true} userid={user.Id} firstname={user.firstName}
lastname={user.lastName} useremail={user.Email} mobilenumber={user.mobileNumber} dateofbirth={user.dateOfBirth} onHide = {editModalClose} /> , document.getElementById('root')) }}>
Edit User
</Button>
</ButtonToolbar>
</td>
<td>
<Button variant="outline-danger" onClick={()=> this.deleteUser(user.Id)} >Delete</Button>
</td>
</tr>
)}
</tbody>
</Table>
</div>
)
}
}
Why is the modal not exiting properly? or what way could i make this possible? Clicking off the modal, cancel or the X button don't seem to close the modal.
======================= EDIT =======================================
I realized, when the modal is in that state, and I submit the edit form, the console displays a "Failed" message from thi chunk of code, even though when I refresh the page, it successfully loads the new edited information.
handleSubmit(event){
event.preventDefault();
fetch(BASE_API_URL,{
method:'PUT',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
Id: event.target.Id.value,
firstName: event.target.firstName.value,
lastName: event.target.lastName.value,
Email: event.target.Email.value,
mobileNumber: event.target.mobileNumber.value,
dateOfBirth: event.target.dateOfBirth.value,
lastModified: currentDate
})
})
.then(res=> res.json())
.then((result) =>
{
console.log(result);
},
(error) => {
console.log('Failed')
}
)
}
It's a sketch... but something like this:
export class User extends Component {
constructor(props){
super(props);
this.state = {users:[], addModalShow : false, editModalShow: false, currentEdited: null}
}
addModalClose =() => this.setState({addModalShow:false});
editModalClose =() => this.setState({editModalShow:false});
render(){
const {users, currentEdited} = this.state;
return(
<div>
<ButtonToolbar>
<Button variant='outline-dark' style={{margin:"auto"}} onClick={()=> this.setState({addModalShow:true})}>
Add User
</Button>
<AddUserModal show={this.state.addModalShow} onHide={this.addModalClose} />
</ButtonToolbar>
<Table responsive borderless style={{borderRadius:"0.3em"}} striped hover size="sm" variant="dark" className="mt-4">
<thead>
<tr>
<th>Id</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Mobile Number</th>
<th>Date of Birth</th>
<th>Last Modified</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{users.map(user=>
<tr key = {user.Id}>
<td>{user.Id}</td>
<td>{user.firstName}</td>
<td>{user.lastName}</td>
<td>{user.Email}</td>
<td>{user.mobileNumber}</td>
<td>{moment(new Date(user.dateOfBirth)).format('YYYY-MM-DD')}</td>
<td>{user.lastModified}</td>
<td>
<ButtonToolbar>
<Button className="mr-2" variant="outline-light" onClick={()=> { this.setState({ currentEdited: user, editModalShow: true }); }}>
Edit User
</Button>
</ButtonToolbar>
</td>
<td>
<Button variant="outline-danger" onClick={()=> this.deleteUser(user.Id)} >Delete</Button>
</td>
</tr>
)}
</tbody>
</Table>
<EditUserModal show={this.state.editModalShow} onHide={this.editModalClose} {...currentEdited} />
</div>
)
}
}
It's because you have hardcoded show prop to true.
<EditUserModal show={this.state.editModalShow} {...otherProps} />
export class User extends Component {
constructor(props){
super(props);
this.state = {users:[], addModalShow : false, editModalShow: false}
}
render(){
const {users, userid, firstname, lastname, useremail, mobilenumber, dateofbirth, lastmodified} = this.state;
let addModalClose =() => this.setState({addModalShow:false});
let editModalClose =() => this.setState({editModalShow:false});
return(
<div>
<ButtonToolbar>
<Button variant='outline-dark' style={{margin:"auto"}} onClick={()=> this.setState({addModalShow:true})}>
Add User
</Button>
<AddUserModal show={this.state.addModalShow} onHide={addModalClose} />
</ButtonToolbar>
<Table responsive borderless style={{borderRadius:"0.3em"}} striped hover size="sm" variant="dark" className="mt-4">
<thead>
<tr>
<th>Id</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Mobile Number</th>
<th>Date of Birth</th>
<th>Last Modified</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{users.map(user=>
<tr key = {user.Id}>
<td>{user.Id}</td>
<td>{user.firstName}</td>
<td>{user.lastName}</td>
<td>{user.Email}</td>
<td>{user.mobileNumber}</td>
<td>{moment(new Date(user.dateOfBirth)).format('YYYY-MM-DD')}</td>
<td>{user.lastModified}</td>
<td>
<ButtonToolbar>
<Button className="mr-2" variant="outline-light" onClick={()=> { this.setState({ editShowModal: true }); }}>
Edit User
</Button>
<EditUserModal show={this.state.editModalShow} userid={user.Id} firstname={user.firstName}
lastname={user.lastName} useremail={user.Email} mobilenumber={user.mobileNumber}
dateofbirth={user.dateOfBirth} onHide={editModalClose} />
</ButtonToolbar>
</td>
<td>
<Button variant="outline-danger" onClick={()=> this.deleteUser(user.Id)} >Delete</Button>
</td>
</tr>
)}
</tbody>
</Table>
</div>
)
}
}

Categories

Resources