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.
Related
I have this React table in JHipster project:
<div className="table-responsive">
{activePairsList && activePairsList.length > 0 ? (
<Table responsive>
<thead>
<tr>
<th className="hand" onClick={sort('id')}>
ID <FontAwesomeIcon icon="sort" />
</th>
<th className="hand" onClick={sort('exchangeId')}>
Exchange Id <FontAwesomeIcon icon="sort" />
</th>
...........
<th />
</tr>
</thead>
<tbody>
{activePairsList.map((activePairs, i) => (
<tr key={`entity-${i}`} data-cy="entityTable">
<td>
<Button tag={Link} to={`${match.url}/${activePairs.id}`} color="link" size="sm">
{activePairs.id}
</Button>
</td>
<td>{activePairs.exchangeId}</td>
</tr>
))}
</tbody>
</Table>
) : (
!loading && <div className="alert alert-warning">No Active Pairs found</div>
)}
</div>
I would like to add search functionality for this table. I want to add Filter by exchange to be present and when any exchange is selected the table should be filtered to show only data for the selected exchange. Do you know how this can be implemented?
I've worked on your issue in stackblitz. I create a link to a simple sample of what you want you can check it here.
I've added an input to filter data is passing to the table on input changes. Hope you find it useful.
I prepared a ReactJS/Typescript solution and implemented it on the JHipster 7.
NOTE: if you have no active-pairs entity, apply the below steps.Else continue from step 4.
First of all, create a monolith web project with JHipster 7 & ReactJS.
Create an entity of ActivePairs with JDL Studio and download
the JDL file from the JDL Studio. (activepairs-jdl.jdl)
If you want to pagination add this expression in your jdl file : paginate all with pagination
Copy the activepairs-jdl.jdl file to the root folder of your
project.
Open a terminal on the root folder of your project and write below command:
jhipster jdl activepairs-jdl.jdl
Go this path in your project :
src>main>webapp>app>entities>active-pairs>active-pairs.tsx
Copy the below code and paste it in your active-pairs.tsx file.
import { connect } from 'react-redux';
import { Link, RouteComponentProps } from 'react-router-dom';
import { Button, Col, Row, Table } from 'reactstrap';
import { ICrudGetAllAction, ICrudSearchAction } from 'react-jhipster';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { IRootState } from 'app/shared/reducers';
import { getEntities } from './active-pairs.reducer';
import { IActivePairs } from 'app/shared/model/active-pairs.model';
import { APP_DATE_FORMAT, APP_LOCAL_DATE_FORMAT } from 'app/config/constants';
export interface IActivePairsProps extends StateProps, DispatchProps, RouteComponentProps<{ url: string }> { }
export const ActivePairs = (props: IActivePairsProps) => {
useEffect(() => {
props.getEntities();
}, []);
const { activePairsList, match, loading = true } = props;
const myDataSource = props.activePairsList;
const [myActivePairsList, setActivePairsList] = useState(props.activePairsList);
const [dropdownList, setDropdownList] = useState([])
const [focus, setFocus] = useState(false)
const [searchValue, setSearchValue] = useState('')
const [arrOfSelectedExId, setArrOfSelectedExId] = useState([])
useEffect(() => {
const unrepeated = activePairsList.reduce((acc, curr) => {
if (acc.find(item => item.exchangeId === curr.exchangeId)) {
return acc
}
return acc.concat(curr)
}, [])
const regexes = [`${searchValue}`];
const filtered = unrepeated.filter(item => regexes.some(regex => item.exchangeId.match(regex)));
setDropdownList(filtered);
setActivePairsList(activePairsList);
}, [searchValue, activePairsList])
useEffect(() => {
if (arrOfSelectedExId.length) {
setActivePairsList(myDataSource.filter(activePairs => {
return arrOfSelectedExId.includes(activePairs.exchangeId)
}))
} else {
setActivePairsList(myDataSource)
}
}, [arrOfSelectedExId])
return (
<div>
<input value={searchValue} onFocus={() => setFocus(true)} onBlur={(e) => setFocus(false)} onChange={e => setSearchValue(e.target.value)} />
{(dropdownList.length !== 0) && focus && (<div className="dropdown-parent">
{
dropdownList.map((item, i) => {
return <div key={'drp' + i} className={arrOfSelectedExId.includes(item.exchangeId) ? 'selected' : ''} onMouseDown={(e) => {
e.preventDefault()
setArrOfSelectedExId(prev => {
if (prev.includes(item.exchangeId)) {
return prev.filter(x => x !== item.exchangeId)
} else {
return prev.concat(item.exchangeId)
}
})
// setSearchValue(item.exchangeId)
}}>{item.exchangeId}</div>
})
}
</div>)}
<h2 id="active-pairs-heading">
Active Pairs
<Link to={`${match.url}/new`} className="btn btn-primary float-right jh-create-entity" id="jh-create-entity">
<FontAwesomeIcon icon="plus" />
Create new Active Pairs
</Link>
</h2>
<div className="table-responsive">
{myActivePairsList && myActivePairsList.length > 0 ? (
<Table responsive>
<thead>
<tr>
<th>ID</th>
<th>Exchange Id</th>
<th />
</tr>
</thead>
<tbody>
{myActivePairsList.map((activePairs, i) => (
<tr key={`entity-${i}`}>
<td>
<Button tag={Link} to={`${match.url}/${activePairs.id}`} color="link" size="sm">
{activePairs.id}
</Button>
</td>
<td>{activePairs.exchangeId}</td>
<td className="text-right">
<div className="btn-group flex-btn-group-container">
<Button tag={Link} to={`${match.url}/${activePairs.id}`} color="info" size="sm">
<FontAwesomeIcon icon="eye" /> <span className="d-none d-md-inline">View</span>
</Button>
<Button tag={Link} to={`${match.url}/${activePairs.id}/edit`} color="primary" size="sm">
<FontAwesomeIcon icon="pencil-alt" /> <span className="d-none d-md-inline">Edit</span>
</Button>
<Button tag={Link} to={`${match.url}/${activePairs.id}/delete`} color="danger" size="sm">
<FontAwesomeIcon icon="trash" /> <span className="d-none d-md-inline">Delete</span>
</Button>
</div>
</td>
</tr>
))}
</tbody>
</Table>
) : (
!loading && <div className="alert alert-warning">No Active Pairs found</div>
)}
</div>
</div>
);
};
const mapStateToProps = ({ activePairs }: IRootState) => ({
activePairsList: activePairs.entities,
loading: activePairs.loading,
});
const mapDispatchToProps = {
getEntities,
};
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
export default connect(mapStateToProps, mapDispatchToProps)(ActivePairs);
copy below css codes in your app.scss file :
h1,
p {
font-family: sans-serif;
}
.selected {
background-color: rgb(190, 188, 188);
}
.dropdown-parent {
max-height: 80px;
width: 200px;
overflow-y: scroll;
border: 1px solid black;
background-color: white;
position: absolute;
}
Run this command ./mvnw
You should see a search box at the top of your table.
As you see I selected 98 and It listed just the rows which have the
values of ExchangeID is 98
Thanks.
enter image description here
Hello, we are currently experiencing the following errors in React. I'm not sure what's wrong with this error and it's being sent out. I tried to cover it with a tag instead of a <React.Fragment>, but the error above keeps appearing on the screen.
I think you're saying the wrong value is in the wrong tag. but I think, not found a problem with my code.
What could be wrong? I ask for your help me.
I attach my code.
import React, { useEffect, Fragment } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Helmet } from "react-helmet";
import {
POST_DETAIL_LOADING_REQUEST,
POST_DELETE_REQUEST,
USER_LOADING_REQUEST,
} from "../../redux/types";
import { Button, Row, Col } from "reactstrap";
import { Link } from "react-router-dom";
import CKEditor from "#ckeditor/ckeditor5-react";
import GrowingSpinner from "../../components/spinner/Spinner";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import {
faPencilAlt,
faCommentDots,
faMouse,
} from "#fortawesome/free-solid-svg-icons";
import BallonEditor from "#ckeditor/ckeditor5-editor-balloon/src/ballooneditor";
import BalloonEditor from "#ckeditor/ckeditor5-editor-balloon/src/ballooneditor";
import { editorConfiguration } from "../../components/editor/EditorConfig";
const PostDetail = (req) => {
const dispatch = useDispatch();
const { postDetail, creatorId, title, loading } = useSelector(
(state) => state.post
);
const { userId, userName } = useSelector((state) => state.auth);
console.log(req);
useEffect(() => {
dispatch({
type: POST_DETAIL_LOADING_REQUEST,
payload: req.match.params.id,
});
dispatch({
type: USER_LOADING_REQUEST,
payload: localStorage.getItem("token"),
});
});
const onDeleteClick = () => {
dispatch({
type: POST_DELETE_REQUEST,
payload: {
id: req.match.params.id,
token: localStorage.getItem("token"),
},
});
};
const EditButton = (
<div>
<Row className="d-flex justify-content-center pb-3">
<Col className="col-md-3 mr-md-3">
<Link to="/" className="btn btn-primary btn-block">
Home
</Link>
</Col>
<Col className="col-md-3 mr-md-3">
<Link
to={`/post/${req.match.params.id}/edit`}
className="btn btn-success btn-block"
>
Edit Post
</Link>
</Col>
<Col className="col-md-3">
<Button className="btn-block btn-danger" onClick={onDeleteClick}>
Delete
</Button>
</Col>
</Row>
</div>
);
const HomeButton = (
<div>
<Row className="d-flex justify-content-center pb-3">
<Col className="col-sm-12 com-md-3">
<Link to="/" className="btn btn-primary btn-block">
Home
</Link>
</Col>
</Row>
</div>
);
const Body = (
<div>
{userId === creatorId ? EditButton : HomeButton}
<Row className="border-bottom border-top border-primary p-3 mb-3 d-flex justify-content-between">
{(() => {
if (postDetail && postDetail.creator) {
return (
<div>
<div className="font-weight-bold text-big">
<span className="mr-3">
<Button color="info">
{postDetail.category.categoryName}
</Button>
</span>
{postDetail.title}
</div>
<div className="align-self-end">{postDetail.creator.name}</div>
</div>
);
}
})()}
</Row>
{postDetail && postDetail.comments ? (
<div>
<div className="d-flex justify-content-end align-items-baseline small">
<FontAwesomeIcon icon={faPencilAlt} />
<span> {postDetail.date}</span>
<FontAwesomeIcon icon={faCommentDots} />
<span>{postDetail.comments.length}</span>
<FontAwesomeIcon icon={faMouse} />
<span>{postDetail.views}</span>
</div>
<Row className="mb-3">
<CKEditor
editor={BalloonEditor}
data={postDetail.contents}
config={editorConfiguration}
disabled="true"
/>
</Row>
</div>
) : (
<h1>hi</h1>
)}
</div>
);
return (
<div>
<Helmet title={`Post | ${title}`} />
{loading === true ? GrowingSpinner : Body}
</div>
);
};
export default PostDetail;
It seems to be a small syntax error, your final return statement should be :
return (
<div>
<Helmet title={`Post | ${title}`} />
{loading === true ? <GrowingSpinner /> : <Body />}
</div>
);
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.
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.
I have this array of rows that I try to sort alphabetically with the sortByTitle() function. The sort method I am pretty sure is OK but there must be something with where I am calling it that makes it not work and it does not mutate the array at all. It may be because of the lifecycle of react.
The sort on getRows() works perfectly.
getHistory() {
if (this.state.historyUser && this.state.historyUser.length) {
return this.state.historyUser.map(x => {
x.state = x.finishDate ? 'closed' : 'open';
return x;
});
} else {
return [];
}
}
getRows() {
let rows = this.state.rows || this.getHistory();
rows.sort((a, b) => b.creationDate - a.creationDate)
return rows.map((x, j) => {
return (
<div key={j} className={`testTable__row testTable__test testTable__test--${x.state}`}>
{this.allTypes.map((type, i) => {
let value = type.className !== 'checks' ? x[type.prop] : x.checked;
if (type.className === 'name') {
value = (
<a href={`/test/${x._id}#1`}>{x[type.prop]}</a>
);
}
return (
<CellUser
key={i}
id={x._id}
value={value}
className={type.className}
changeChecked={this.changeChecked}
isSimulacro={x.isSimulacro}
score={x.scoreProMIR}
/>
);
})}
</div>
);
});
}
handleInputChange(e) {
let rows = this.state.historyUser;
const selector = e.target.getAttribute("label")
rows = rows.filter(elm => elm[selector].toLowerCase().includes(e.target.value.toLowerCase()));
this.setState({ inputValue: e.target.value, rows: rows});
}
sortByTitle() {
let rows = this.state.rows || this.getHistory();
rows.sort((a, b) => a.title.localeCompare(b.title));
this.setState({ rows: row });
}
render() {
return (
<div style={{ height: '100%', width: '100%' }}>
<div className="testTable">
<div className="testTable__row testTable__header">
<div className="testTable__column testTable__column--name">
Nombre
<input type="text" label="title" onChange={this.handleInputChange} />
<button onClick={this.sortByTitle}> Ordenar </button>
</div>
<div className="testTable__column testTable__column--score"> Nota </div>
<div className="testTable__column testTable__column--type"> Tipo </div>
<div className="testTable__column testTable__column--date"> Fecha </div>
<div className="testTable__column testTable__column--state"> Estado </div>
<div className="testTable__column testTable__column--checks">
<label>
Abiertos <Checkbox selected={this.state.checkOpen} onClick={this.allOpened} />
</label>
<label>
Cerrados <Checkbox selected={this.state.checkClose} onClick={this.allClosed} />
</label>
<label>
Todos <Checkbox selected={this.state.selectedAllRows} onClick={this.allRows} />
</label>
</div>
</div>
<div className="testTable__body">
<Scrollbars {...scrollbarsProps()}>{this.getRows()}</Scrollbars>
</div>
<div
className={`testTable__row testTable__footer${
this.state.btnClose || this.state.btnReset || this.state.btnReopen ? ' active' : ''
}`}
>
<ReactCSSTransitionGroup
component="div"
transitionName="topBottom"
transitionEnterTimeout={0}
transitionLeaveTimeout={0}
>
{this.state.btnClose ? (
<button className="button button--close" onClick={this.requestAction} name="close">
Cerrar seleccionados
</button>
) : null}
{this.state.btnReset ? (
<button className="button button--reset" onClick={this.requestAction} name="reset">
Resetear seleccionados
</button>
) : null}
{this.state.btnReopen ? (
<button className="button button--open" onClick={this.requestAction} name="open">
Reabrir seleccionados
</button>
) : null}
{this.state.btnAddToStats ? (
<button className="button button--add" onClick={this.requestAction} name="add">
Añadir a estadísticas
</button>
) : null}
</ReactCSSTransitionGroup>
</div>
</div>
<ReactCSSTransitionGroup
component="div"
transitionName="topBottom"
className={`superCoverMsg${this.state.confirmAction ? '' : ' none'}`}
transitionEnterTimeout={0}
transitionLeaveTimeout={0}
>
{this.state.confirmAction ? (
<div className="coverMsg confirmPopUp" key="0">
<p>{this.state.textAction}</p>
<div className="coverLabelInput coverLabelInput__botones columnWidth">
<ul className="cien">
<li className="cincuenta cancelar">
<a onClick={this.removeConfirmAction} href="#" title="Cancelar">
Cancelar
</a>
</li>
<li className="cincuenta aceptar">
<a onClick={this.aceptAction} href="#" title="Aceptar">
Aceptar
</a>
</li>
</ul>
</div>
</div>
) : null}
</ReactCSSTransitionGroup>
</div>
);
}
}
It looks like your setting rows equal to row, which I don't see defined. Maybe change this
this.setState({ rows: row });
to
this.setState({ rows: rows });
Also I think the react-friendly way to modify an array from state would be use a spread operator so as not to mutate the state object directly, like so:
let rows = [...this.state.rows] || this.getHistory();
sortByTitle() {
let rows = this.state.rows || this.getHistory();
rows.sort((a, b) => a.title.localeCompare(b.title));
this.setState({ rows: row });
}
You are mutating the state. instead copy the content into separate new array, sort it and use that new variable in .setState.