I am trying to add new row onclick of accordion i.e while expand using reactable, attached the expected result.
I have showed the table structured data using Tr and Td from reactable but however, not sure to add the new row.
onclick of the arrow the dynamic row should expand,I tried to do so but wasn't able to achieve that.
class PolicyDetails extends Component {
showPolicyOperation = (e,models) => {
e.preventDefault();
const {callbacks} = this.props
const activeClass = document.querySelectorAll('.fa-angle-up')
const currentTarget = e.currentTarget;
if(currentTarget.classList.contains('fa-angle-up')){
currentTarget.classList.remove('fa-angle-up');
currentTarget.classList.add('fa-angle-down');
}else{
currentTarget.classList.remove('fa-angle-down');
currentTarget.classList.add('fa-angle-up');
}
activeClass && activeClass.forEach(node => {
node.classList.remove('fa-angle-up');
node.classList.add('fa-angle-down');
})
callbacks.fetchPoliciesWithId(models.id)
}
getHeaders = () => {
let headers = ([
<Th key="0" column=""></Th>,
<Th key="1" column="id">Policy Id</Th>,
<Th key="2" column="serviceType">Service</Th>,
<Th key="3" column="name">Policy Name</Th>,
<Th key="4" column="description">Policy Description</Th>,
<Th key="5" column="policyLabel">Policy Label</Th>,
<Th key="6" column="policyType">Policy Type</Th>,
<Th key="7" column="operation">Operation</Th>,
<Th key="8" column="action">Actions</Th>
])
return headers;
}
pageChange = (page) => {
this.cPoliciesData.params.page = page - 1 || undefined;
this.props.callbacks.fetchPolicies();
}
getRows = (models, idx) => {
const state = this.props.options._vState
let rows = ([
<Td key="0" column="">
<i className="fa pointer fa-angle-down"
aria-hidden="true" key = {idx} onClick={e => {
state.isPolicySelected = !state.isPolicySelected;
this.showPolicyOperation(e,models)
}}></i></Td>,
<Td key="1" column="id">{<a>{models.id}</a>}</Td>,
<Td key="2" column="serviceType">{models.serviceType || "--"}</Td>,
<Td key="3" column="name">{models.name || "--"}</Td>,
<Td key="4" column="description">{models.description || "--"}</Td>,
<Td key="5" column="policyLabel">{"--"}</Td>,
<Td key="6" column="policyType">{models.serviceType == 'tag' && models.policyType == 0 ? "Tag Based" : POLICY_TYPE[models.policyType].label}</Td>,
<Td key="7" column="operation">{"--"}</Td>,
<Td key="8" column="action">{"--"}</Td>,
]);
let operation = state.isPolicySelected && <Tr className="special-row">
<Th column="name">
<strong className="name-header">First Name, Last Name</strong>
</Th>
<Th column="age">
<em className="age-header">Age, years</em>
</Th>
</Tr>
rows.push(operation)
return rows;
}
render() {
const {options , callbacks} = this.props;
const {cPoliciesData, _vState} = options
return (
<Row className="m-t-md">
{/* <Col md={12}> */}
<PanelBody>
<Table data={cPoliciesData}
tableAttr={{ className: "table table-hover" }}
getHeaders={this.getHeaders}
getRowData={this.getRows}
pagination={true}
pageChange={this.pageChange}
>
</Table>
</PanelBody>
{/* </Col> */}
</Row>
)
}
}
You just need to add in array . and then with
UseEffect(()=>{
},[options._vState])
Related
When someone Logs in first of all i want to show the currentUserData in the table body.
then when clicks on "Today" button, table should be show the "todayData"....when clicks on "This Week" button, table should be show the "thisWeekData"....etc....
references
..................
userData = all datas available in database,
todayData = filtered data from "userData" with current day (function calls after clicking "Today" button from main page),
thisWeekData = filtered data from "userData" with current week (function calls after clicking "This Week" button from main page)
thisMonthData = filtered data from "userData" with current Month (function calls after clicking "This Month" button from main page),
customData = filtered data from "userData" between dates (function calls after clicking "Custom" button from main page),
dropDownUserData = filtered data from "userData" (function calls after clicking any user from Drop down menu "Today" available in main page),
currentUserData = displaying datas of users by deviding into pages
{
// 👇️checking whether any current day datas available or not...if, displaying the datas
todayData.length > 0 ?
todayData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>)
:
// 👇️checking whether any this week datas available or not...if, displaying the datas
thisWeekData.length > 0 ?
thisWeekData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>
)
:
// 👇️checking whether any this month datas available or not...if, displaying the datas
thisMonthData.length > 0 ?
thisMonthData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>
)
:
// 👇️checking whether any custom selected datas available or not...if, displaying the datas
customData.length > 0 ?
customData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>
)
:
// 👇️checking whether any datas related to selected user from drop down is available or not...if, displaying the datas
dropDownUserData ?
dropDownUserData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>
)
:
// 👇️checking whether any datas available in database or not...if, displaying the datas
currentUserData && currentUserData.length > 0 ?
// 👇️Search details
currentUserData.filter((value) => {
if (searchInput === '') {
return value
}
else if (value.name.toLowerCase().includes(searchInput.toLowerCase())) {
return value
}
})
// 👇️Displaying datas on table
.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>
) : 'Loading'
}
</tbody>
//👇️ Setting state for showing the required datas when filtering
const [showUserData, setShowUserData] = useState(false)
const [showTodayData, setShowTodayData] = useState(false)
const [showWeekData, setShowWeekData] = useState(false)
const [showMonthData, setShowMonthData] = useState(false)
const [showCustomData, setShowCustomData] = useState(false)
const [showDropDownData, setShowDropDownData] = useState(false)
setstates as true or false as per the requirements in the onClick functions
eg: for Today button click
setShowTodayData(true)
setShowWeekData(false)
setShowDropDownData(false) etc.....
app.js
{
<tbody className='table-body'>
// 👇️Displaying all datas by deviding into pages
{showUserData && currentUserData.filter((value) => {
if (searchInput === '') {
return value
}
else if (value.name.toLowerCase().includes(searchInput.toLowerCase())) {
return value
}
})
.map((user, id) => {
return <tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>
})
}
// 👇️checking whether any datas related to selected user from drop down is available or not...if, displaying the datas
{showDropDownData && dropDownUserData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>)
}
// 👇️checking whether any Today datas available or not...if, displaying the datas
{showTodayData && todayData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>)
}
// 👇️checking whether any This week datas available or not...if, displaying the datas
{showWeekData && thisWeekData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>)
}
// 👇️checking whether any This month datas available or not...if, displaying the datas
{
showMonthData && thisMonthData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>)
}
// 👇️checking whether any Custom datas available or not...if, displaying the datas
{
showCustomData && customData.map((user, id) =>
<tr key={id} className='table-row'>
<td className='table-item'>{user.date}</td>
<td className='table-item'>{user.from}</td>
<td className='table-item'>{user.to}</td>
<td className='table-item'>{user.duration}</td>
<td className='table-item'>{user.hangup}</td>
<td className='table-item'>{user.action}</td>
</tr>)
}
</tbody>
}
Create memoized todayData, thisWeekData, and thisMonthData.
const todayData = useMemo(() => {
...
},[userData])
const thisWeekData = useMemo(() => {
...
},[userData])
const thisMonthData = useMemo(() => {
...
},[userData])
Then create a showingData state that would become render reference data
const [showingData, setShowingData] = useState();
render (
...
{showingData.map((data) => {
})}
...
)
Finally, at the buttons, assign the data by using setState:
render (
...
<botton onClick={() => setShowingData(todayData)}>
Today
</button>
<botton onClick={() => setShowingData(thisWeekData)}>
This Week
</button>
<botton onClick={() => setShowingData(thisMonth)}>
This Month
</button>
...
)
And the example is as follows:
function makeUserData() {
const daysInMonth = [];
const monthDate = moment().startOf('isoWeek');
_.times(monthDate.daysInMonth(), function (n) {
const hours = Math.random() * (0 + 12) + 0
const minutes = Math.random() * (0 + 60) + 0
const start = moment(n).set("hour", hours).set("minute", minutes);
const end = moment(start).add(Math.random() * (0 + 30) + 0, 'minutes');
daysInMonth.push({
date: monthDate.format('MM/DD/YYYY'),
name: monthDate.format('dddd'),
from: start.format("HH:mm"),
to: end.format("HH:mm"),
duration: `${parseInt((moment(end) - moment(start))/60000)} minutes`
});
monthDate.add(1, 'day');
});
return daysInMonth;
}
const { useEffect, useState, useMemo } = React;
function App() {
const [showingData, setShowingData] = useState([]);
const today = useMemo(() => moment());
const userData = useMemo(() => {
return makeUserData();
},[]);
useEffect(() => {
setShowingData(userData);
}, [userData]);
const todayData = useMemo(() => {
return userData.filter((data) => data.date === today.format('MM/DD/YYYY'));
}, [today, userData]);
const thisWeekData = useMemo(() => {
const startOfWeek = today.clone().startOf('isoWeek');
const endOfWeek = today.clone().endOf('isoWeek');
return userData.filter((data) => {
return (new Date(data.date) >= new Date(startOfWeek) && new Date(data.date) <= new Date(endOfWeek))
});
}, [today, userData]);
const thisMonthData = useMemo(() => {
const startDate = today.clone().startOf('month');
return userData.filter((data) => new Date(data.date) >= new Date(startDate));
}, [today, userData]);
return (
<div>
<button onClick={() => setShowingData(userData)}>
Current Data
</button>
<button onClick={() => setShowingData(todayData)}>
Today
</button>
<button onClick={() => setShowingData(thisWeekData)}>
This Week
</button>
<button onClick={() => setShowingData(thisMonthData)}>
This Month
</button>
<table>
<thead>
<tr>
<th>Date</th>
<th>Name</th>
<th>From</th>
<th>To</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
{showingData.map((data, index) => (
<tr key={index}>
<td>{data.date}</td>
<td>{data.name}</td>
<td>{data.from}</td>
<td>{data.to}</td>
<td>{data.duration}</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<div class='react'></div>
I have a table that is powered by data coming from Firebase.
In the table listing, I have the option to generate the pdf of the entire history, with the map function.
But I would also like to generate the pdf of a single item when selecting the 'pdf' icon in the 'actions' column. But I'm not able to get only the line when I select the icon, could you help me?
// List code
useEffect(function(){
let listaEPI = [];
firebase.firestore().collection('epis').get().then(async function(resultado){
await resultado.docs.forEach(function(doc){
// console.log(doc.id)
if (doc.data().nome.indexOf(busca) >= 0){
listaEPI.push({
id: doc.id,
nome: doc.data().nome,
funcao: doc.data().funcao
});
}
})
setEpis(listaEPI);
})
});
return <div className='table table-bordered table-responsive'>
<table className="table">
<thead>
<tr className='text-center'>
{/* <th scope='row'> # </th> */}
<th scope='col'> Nome </th>
<th scope='col'> Função </th>
<th scope='col' className='col-acao'> Ações </th>
</tr>
</thead>
{
props.arrayEpis.map((epi) => {
return <tr key={epi.key} className="text-center">
<td className='nome'> {epi.nome} </td>
<td> {epi.funcao} </td>
<Link to='#' onClick={(e) => epiIndPDF(epis)}> <i className='far fa-file-pdf'></i> </Link>
</td>
</tr>
})
}
</table>
</div>
// Code trying to get the values of the selected row
function epiIndPDF(epis){
pdfMake.vfs = pdfFonts.pdfMake.vfs;
var nRe;
const filterDad = "";
var e;
const dados = epis.map((epi) => {
return [
epi.nome,
epi.funcao,
epi.numero_registro,
nRe = epi.numero_registro,
console.log(nRe)
]
})
console.log(filterDad);
// console.log(...dados);
// for (var i = 0; i < dados.length; i++){
// const found = dados.find(epi => {
// return epi.key === epi.key;
// })
// console.log(found)
// }
const docDefinitios = {
pageSize: 'A4',
pageOrientation: 'landscape', // Orientação da página
pageMargins: [10, 50, 10, 40],
header: [header],
content: [infor2, termo, assinat],
// footer: [Rodape]
}
pdfMake.createPdf(docDefinitios).download();
}
export default epiIndPDF;
Here I have got the two .json files named users.json and subscription.json. In JSON file users.id links to subscription.user_id. I have view the data of subscription.json in the table.
Now I want to get the username using id of users.json linked to user_id of subscription.json
import React, {useEffect, useState} from 'react'
import '../UserList/userlist.css'
const Suscriber = () => {
const [search, setSearch] = useState([]);
const [data,setData]=useState([]);
const [order, setorder] = useState("ASC");
const [users,setUsers] = useState([{}])
useEffect(()=>{
fetch('data/users.json').then((res)=>res.json()).then((data)=>{
setUsers(data)
})
},[])
const getData=()=>{
fetch('./data/subscriptions.json'
,{
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}
)
.then(function(response){
console.log(response)
return response.json();
})
.then(function(myJson) {
console.log(myJson);
setData(myJson)
});
}
useEffect(()=>{
getData()
},[])
const sorting = (col) => {
if (order === "ASC") {
const sorted = [...data].sort((a,b)=>
a[col].toString().toLocaleLowerCase() > b[col].toString().toLocaleLowerCase() ? 1 : -1
// ||
// a[col].Number.toLocaleLowerCase() < b[col].Number.toLocaleLowerCase() ? 1 : -1
);
setData(sorted);
setorder("DSC");
}
if (order === "DSC") {
const sorted = [...data].sort((a,b)=>
a[col].toString().toLocaleLowerCase() < b[col].toString().toLocaleLowerCase() ? 1 : -1
);
setData(sorted);
setorder("ASC");
}
}
return (
<div className="main">
<div className="search_option">
<h1 className="table-head">Subscribed User Data List</h1>
<div className="input-icons">
<i class="fa fa-search icon" aria-hidden="true"></i>
<input type="search"
className="input-field"
placeholder="Search......."
onChange={(event) => {
setSearch(event.target.value);
}}
/>
</div>
</div>
<table>
<thead>
<tr>
<th scope="col" onClick={()=>sorting("id")}>ID <i class="fas fa-sort sortings"></i></th>
<th scope="col" onClick={()=>sorting("user_id")}>User ID <i class="fas fa-sort sortings"></i></th>
<th scope="col">Username <i class="fas fa-sort sortings"></i></th>
<th scope="col" onClick={()=>sorting("package")}>Package <i class="fas fa-sort sortings"></i></th>
<th scope="col" onClick={()=>sorting("expires_on")}>Expire on <i class="fas fa-sort sortings"></i></th>
</tr>
</thead>
<tbody>
{data.filter((val) => {
if (search === ""){
return val
}
else if (
val.id.toString().toLocaleLowerCase().includes(search.toString().toLocaleLowerCase())
// || val.email.toLocaleLowerCase().includes(search.toLocaleLowerCase())
// || val.user_id.toString().toLocaleLowerCase().includes(search.toLocaleLowerCase())
|| val.package.toLocaleLowerCase().includes(search.toString().toLocaleLowerCase())
// || val.expires_on.toString().toLocaleLowerCase().includes(search.toLocaleLowerCase())
){
return val
}
return false;
}).map((val, key) => {
const user = users.find(uid => uid.id === val.user_id);
return <tr key={key}>
<td data-label="ID">{val.id}</td>
<td data-label="User ID">{val.user_id}</td>
<td data-label="Username">{user.username}
{/* {
subscribe.map((detail, index) => {
return <div>{detail.username}</div>
})
} */}
{/* {
subscribe.filter(uid => uid.id === val.user_id).map(details =>(
<>{details.username}</>
))
} */}
</td>
<td data-label="Package">{val.package}</td>
<td data-label="Expire on">{val.expires_on}</td>
</tr>
})}
</tbody>
</table>
</div>
)
}
export default Suscriber
The table includes all the data in subscriptions.json now need to find and display the same user_id and username from users.json and view it on the table below.
Below are users.json data picture:
Below are subscriptions.json data picture:
Instead of using Filter you can use the find method .
.map((val, key) => {
// Find the user
const user = subscribe.find(uid => uid.id === Number(val.user_id));
return <tr key={key}>
<td data-label="ID">{val.id}</td>
<td data-label="User ID">{val.user_id}</td>
<td data-label="Username">{ user?.username || '-' }</td>
<td data-label="Package">{val.package}</td>
<td data-label="Expire on">{val.expires_on}</td>
</tr>
})}
I made a table with a dropdown menu that will filter the data shown. It loads correctly and I can toggle the individual teams but when I try to select All Teams (index 0) again I get an error saying property 'name' is undefined.
What is wrong and how do I fix it?
import React, { useState } from "react";
import "./styles.css";
import { flavours } from "./mock-data";
export default function App() {
const [selectedFilter, setFilter] = useState(0);
// start table
const header = [
{ title: "Banana" },
{ title: "Chocolate" },
{ title: "Vanilla" },
{ title: "Total" }
];
// render Table Headers
const renderTableHeader = () =>
header.map((e, index) => {
const { title } = e;
return (
<th key={Number(index)}>
{title}
</th>
);
});
const renderAllTeamData = () =>
flavours.map((team) => {
const { name, banana, chocolate, vanilla } = team; // destructuring
return (
<tr key={team.name}>
<th
style={{ textAlign: "start" }}
>
{name}
</th>
<td>{banana.length}</td>
<td>{chocolate}</td>
<td>{vanilla}</td>
<td>
{banana.length + chocolate + vanilla}
</td>
</tr>
);
});
const renderTeamData = () => {
const { name, banana, chocolate, vanilla } = flavours[selectedFilter - 1]; // destructuring
return (
<tr>
<th style={{ textAlign: "start" }}>
{name}
</th>
<td>{banana.length}</td>
<td>{chocolate}</td>
<td>{vanilla}</td>
<td>{banana.length + chocolate + vanilla}</td>
</tr>
);
};
return (
<div className="App">
<form>
<select
value={selectedFilter}
onChange={(e) => setFilter(e.currentTarget.value)}
>
<option value={0}>All Teams</option>
{flavours.map((value, index) => (
<option key={value.name} value={index + 1}>
{value.name}
</option>
))}
</select>
</form>
<table>
<thead>
<tr>
<th> </th>
{renderTableHeader()}
</tr>
</thead>
<tbody>
{selectedFilter === 0 ? renderAllTeamData() : renderTeamData()}
</tbody>
</table>
</div>
);
}
Here is a code sandbox too https://codesandbox.io/s/nice-brattain-pwnbr?file=/src/App.js
The problem is here
{selectedFilter === 0 ? renderAllTeamData() : renderTeamData()}
Here you are using === which is comparing against value and type but you set the currentTarget.value which is a string, so the comparison fails and moved to the else part
<select
value={selectedFilter}
onChange={(e) => setFilter(e.currentTarget.value)}
>
You can fix by changing it to compare by value like below
{selectedFilter == 0 ? renderAllTeamData() : renderTeamData()}
You need to parse e.currentTarget.value to Int.
replace that line with :
onChange={(e) => setFilter(parseInt(e.currentTarget.value, 10))}
and it should work fine.
change the onchange function of your select
<select
value={selectedFilter}
onChange={(e) => {
setFilter(+e.currentTarget.value);
}}
>
<option value={0}>All Teams</option>
{flavours.map((value, index) => (
<option key={value.name} value={index + 1}>
{value.name}
</option>
))}
</select>
or change tbody like this
<tbody>
{selectedFilter == 0 ? renderAllTeamData() : renderTeamData()}
</tbody>
the problem in current scenario is the value u set is integer or number but value u select come as string
Convert the filter value to a number before setting it to state.
setFilter(+e.currentTarget.value)
const [selectedFilter, setFilter] = useState(0);
<form>
<select
value={selectedFilter}
onChange={(e) => setFilter(+e.currentTarget.value)}
>
<option value={0}>All Teams</option>
{flavours.map((value, index) => (
<option key={value.name} value={index + 1}>
{value.name}
</option>
))}
</select>
</form>
I am listing data with api.
I show the data I received to the user with reactstrap table.
but I want to paging.
Up to 6 records are displayed on one page, other records are displayed on the following pages.
import React, { Component, useState } from "react";
import withAuth from "../../components/helpers/withAuth";
import {
Button,
Card,
CardBody,
CardHeader,
Col,
Pagination,
PaginationItem,
PaginationLink,
Row,
Table,
} from "reactstrap";
class CustomerDebt extends Component {
constructor(props) {
super(props);
this.domain = `http://127.0.0.1:8000`;
this.state = {
isLoaded: true,
items: [], //Customer Debt Items
};
}
async componentDidMount() {
//customer debt list
await fetch(
`${this.domain}/api/debt/list?customer=` +
this.props.customerInfo.customer.id,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
"Content-Type": "application/json"
}
}
)
.then(res => {
if (res.ok) {
return res.json();
} else {
return res.json().then(err => Promise.reject(err));
}
})
.then(json => {
this.setState({
items: json,
});
this.abortController.abort();
})
.catch(error => {
return error;
});
}
render() {
const { isLoaded, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className={"animated fadeIn container-fluid"}>
<Row>
<Col>
<Card>
<CardHeader>
<i className="fa fa-align-justify" /> Müşteri Borcu
</CardHeader>
<CardBody>
<Table hover bordered striped responsive size="sm">
<thead>
<tr>
<th width={"10"} />
<th width={"15"}>No</th>
<th style={{ display: "none" }}>User</th>
<th style={{ display: "none" }}>Key</th>
<th style={{ display: "none" }}>CreatedUserKey</th>
<th width={"40"}>Total debt</th>
<th width={"40"}>Received amount</th>
<th scope={"row"}>Description</th>
<th width={"20"}>Payment Date</th>
</tr>
</thead>
<tbody>
{items.map(item => {
return (
<tr key={item.id}>
<td>{item.id}</td>
<td style={{ display: "none" }}>{item.user}</td>
<td style={{ display: "none" }}>{item.debtKey}</td>
<td style={{ display: "none" }}> {" "} {item.createduserKey}{" "} </td>
<td>{item.totalDebt}</td>
<td>{item.receivedAmount}</td>
<td>{item.description}</td>
<td> {new Date(item.paymentDate).toLocaleString()} </td>
</tr>
);
})}
</tbody>
</Table>
<nav>
<Pagination>
<PaginationItem>
<PaginationLink previous tag="button">
Back
</PaginationLink>
</PaginationItem>
<PaginationItem active>
<PaginationLink tag="button">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink tag="button">2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink tag="button">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink tag="button">4</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink next tag="button">
Next
</PaginationLink>
</PaginationItem>
<PaginationItem></PaginationItem>
</Pagination>
</nav>
</CardBody>
</Card>
</Col>
</Row>
</div>
);
}
}
}
export default CustomerDebt;
You need to generate pagination buttons dynamically based on number of records and then on pressing pagination button, set the page number and create an array if items that you want to show based on page number and per page size.
This is sample code to give you an idea how to get this done. This is not complete or bug proof since it is your job. I hope will get the idea.
class CustomerDebt extends Component {
constructor(props) {
super(props);
this.domain = `http://127.0.0.1:8000`;
this.state = {
isLoaded: true,
items: [], //Customer Debt Items,
pageItems: [],
page: 0,
pageSize: 6
};
}
async componentDidMount() {
const { pageSize } = this.state;
//customer debt list
await fetch(
`${this.domain}/api/debt/list?customer=` +
this.props.customerInfo.customer.id,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
"Content-Type": "application/json"
}
}
)
.then(res => {
if (res.ok) {
return res.json();
} else {
return res.json().then(err => Promise.reject(err));
}
})
.then(json => {
this.setState({
items: json,
pageItems: json.slice(0, pageSize)
});
this.abortController.abort();
})
.catch(error => {
return error;
});
}
render() {
const { isLoaded, pageItems, items, page, pageSize } = this.state;
const pages = Math.ceil(items.length / page);
const paginationItems = Array(pages).fill('').map((i, index) => (
<PaginationItem active={page === index}>
<PaginationLink tag="button" onClick={() => this.setState({page: index })}}>2</PaginationLink>
</PaginationItem>
));
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className={"animated fadeIn container-fluid"}>
<Row>
<Col>
<Card>
<CardHeader>
<i className="fa fa-align-justify" /> Müşteri Borcu
</CardHeader>
<CardBody>
<Table hover bordered striped responsive size="sm">
<thead>
<tr>
<th width={"10"} />
<th width={"15"}>No</th>
<th style={{ display: "none" }}>User</th>
<th style={{ display: "none" }}>Key</th>
<th style={{ display: "none" }}>CreatedUserKey</th>
<th width={"40"}>Total debt</th>
<th width={"40"}>Received amount</th>
<th scope={"row"}>Description</th>
<th width={"20"}>Payment Date</th>
</tr>
</thead>
<tbody>
{pageItems.map(item => {
return (
<tr key={item.id}>
<td>{item.id}</td>
<td style={{ display: "none" }}>{item.user}</td>
<td style={{ display: "none" }}>{item.debtKey}</td>
<td style={{ display: "none" }}> {" "} {item.createduserKey}{" "} </td>
<td>{item.totalDebt}</td>
<td>{item.receivedAmount}</td>
<td>{item.description}</td>
<td> {new Date(item.paymentDate).toLocaleString()} </td>
</tr>
);
})}
</tbody>
</Table>
<nav>
<Pagination>
<PaginationItem onClick={() => this.setState(prev => ({page: prev.page -1}))}>
<PaginationLink>
Back
</PaginationLink>
<PaginationItem onClick={() => this.setState(prev => ({page: prev.page + 1}))}>
<PaginationLink next tag="button">
Next
</PaginationLink>
</PaginationItem>
<PaginationItem></PaginationItem>
</Pagination>
</nav>
</CardBody>
</Card>
</Col>
</Row>
</div>
);
}
}
}
export default CustomerDebt;
First of all you need to create two variables that will help you to track current page and size of the table. Let's call them pageSize and pageIndex
class App extends React.Component {
state = {
pageSize: 2, // <- 2 items will be shown on single page
pageIndex: 0, // 0 is a default page to show
items: []
};
...
Then you need to fetch some data from the external source. In my example, I just create a mock array and set it to the state.
...
componentDidMount() {
const data = [
{ id: 1, name: "Roman" },
{ id: 2, name: "Oleh" },
{ id: 3, name: "Vitalii" },
{ id: 4, name: "Mikhail" },
{ id: 5, name: "Vladislav" },
{ id: 6, name: "Anton" },
{ id: 7, name: "Yurii" },
{ id: 8, name: "Volodymir" },
{ id: 9, name: "Taras" }
];
this.setState({ items: data });
}
...
After that, you need to create helper functions and place table navigation logic there. Let's name them handlePrevPageClick and handleNextPageClick.
The handlePrevPageClick should decrease current index on click. Also, we need to prevent user from scrolling to much. So, if pageIndex is not 0 - decrease, otherwise stop decreasing.
The handleNextPageClick should have absolutely the same logic as handlePrevPageClick. The only thing it is reversed. Don't let user overscroll your table. To do that, we need to understand how many pages do we have. By dividing this.state.items / this.state.pageSize we will get the total number of available pages. Let's imagine that our table have 12 items and page size is 5. So, 12 / 5 = 2.4. It means that we will have 2 pages full loaded and 4 items left. By using Math.ceil(12 / 5) we will get 3 - is an integer number of total available pages of the table. After that, we just add simple condition, if pageIndex < 3, if yes - increase pageIndex, otherwise stop.
...
handlePrevPageClick(event) {
this.setState(prevState => ({
pageIndex: prevState.pageIndex > 0 ? prevState.pageIndex - 1 : 0
}));
}
handleNextPageClick(event) {
this.setState(prevState => ({
pageIndex:
prevState.pageIndex <
Math.ceil(prevState.items.length / prevState.pageSize)
? prevState.pageIndex + 1
: prevState.pageIndex
}));
}
The last think is to render your table with correct rows. To do that, you can use .slice(...). First argument is a left boundary of the page, the second one is a right boundary of the page.
First page
this.state.pageIndex * this.state.pageSize, // 0 * 5 = 0
this.state.pageIndex * this.state.pageSize + this.state.pageSize // 0 * 5 + 5 = 5
To show elements from index 0 to 5.
Second page
this.state.pageIndex * this.state.pageSize, // 1 * 5 = 5
this.state.pageIndex * this.state.pageSize + this.state.pageSize // 1 * 5 + 5 = 10
To show elements from index 5 to 10.
...
render() {
return (
<>
<button onClick={event => this.handlePrevPageClick(event)}>
Prev page
</button>
<button onClick={event => this.handleNextPageClick(event)}>
Next page
</button>
<table border="1">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{this.state.items
.slice(
this.state.pageIndex * this.state.pageSize,
this.state.pageIndex * this.state.pageSize + this.state.pageSize
)
.map(item => (
<tr>
<td>{item.id}</td>
<td>{item.name}</td>
</tr>
))}
</tbody>
</table>
</>
);
}
}
If you want to see full working example, please use this CodeSandbox link