Click event with React Table 7 - reactjs

This is my Cell data in column:
import { format } from "date-fns";
export const COLUMNS_ALLLOAN = [
{
Header: "Id",
accessor: "id",
Cell: ({ row }) => Number(row.id) + 1,
},
{
Header: "Account Number",
accessor: "acNumber",
Cell: ({ row }) => <>{row.original.acNumber}</>,
},
{
Header: "Account Name",
accessor: "acName",
},
{
Header: "Loan Type",
accessor: "acType",
Cell: ({ row }) => <>{row.original.acType}</>,
},
{
Header: "Opening Date",
accessor: "acOpen",
Cell: ({ row }) => <>{row.original.acOpen}</>,
},
{
Header: "Sanction Date",
accessor: "acSanction",
Cell: ({ row }) => <>{row.original.acSanction}</>,
},
{
Header: "Expiry Date",
accessor: "acExpiry",
Cell: ({ row }) => <>{row.original.acExpiry}</>,
},
{
Header: "Limit",
accessor: "acLimit",
Cell: ({ row }) => <>{Number(row.original.acLimit)}</>,
},
{
Header: "Outstanding",
accessor: "lastDayBalance",
Cell: ({ row }) => <>{Number(row.original.lastDayBalance)}</>,
},
{
Header: "Overlimit",
accessor: "overlimit",
Cell: ({ row }) => <>{Number(row.original.overLimit)}</>,
},
{
Header: "Available",
accessor: "available",
Cell: ({ row }) => <>{Number(row.original.availableBalance)}</>,
},
{
Header: "Edit",
accessor: "edit",
Cell: ({ row }) => <button className="btn btn-primary">Edit</button>,
},
{
Header: "Delete",
accessor: "X",
Cell: ({ row }) => <button className="btn btn-danger">X</button>,
},
];
This is my page
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import Footer from "../../components/Footer";
import { useMemo } from "react";
import { useTable, useSortBy, useGlobalFilter, usePagination } from "react-table";
import { COLUMNS_ALLLOAN } from "../../components/COLUMNS_ALLLOAN.js";
import Globalfilter from "../../components/Globalfilter";
import { deleteById, getLoans } from "../../features/bradvance/advanceSlice";
const Allloans = () => {
const dispatch = useDispatch();
const { allLoans } = useSelector((state) => state.bradvance);
const navigate = useNavigate();
const goBack = async () => {
navigate(-1);
};
const columns = useMemo(() => COLUMNS_ALLLOAN, []);
const data = useMemo(() => allLoans, []);
// console.log(data);
const tableInstance = useTable(
{
columns,
data: allLoans,
initialState: { pageSize: 30 },
},
useGlobalFilter,
useSortBy,
usePagination
);
const {
headerGroups,
getTableProps,
getTableBodyProps,
page,
prepareRow,
state,
setGlobalFilter,
nextPage,
previousPage,
canNextPage,
canPreviousPage,
pageOptions,
setPageSize,
gotoPage,
pageCount,
} = tableInstance;
const { globalFilter, pageIndex, pageSize } = state;
// console.log(data.length);
const totalLoan = allLoans
.map((item, sl) => {
return item.lastDayBalance;
})
.reduce((acc, curValue) => {
// console.log(curValue);
return acc + curValue;
}, 0);
// console.log(totalLoan);
const handleClick = (id) => {
dispatch(deleteById(id));
alert("Deleted Successfully.");
console.log(id);
};
return (
<>
<div className="container">
<div className="row">
<div className="col">
<div className="summary">
<h1 className="p-4 text-center fw-bold mb-0">All Loans</h1>
</div>
</div>
</div>
<div className="row">
<div className="col">
<Globalfilter filter={globalFilter} setFilter={setGlobalFilter} />
</div>
</div>
<div className="row">
<div className="col">
<div className="summary table-responsive">
<table {...getTableProps()} className="table table-hover table-bordered">
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>{column.render("Header")} </th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td onClick={() => handleClick(row.original.id)} {...cell.getCellProps()}>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</div>
<div className="row ">
<div className="col d-flex justify-content-end">
<ul className="list-group list-group-horizontal">
<li className="list-group-item fw-bold">
Total Loan: <span className="fw-bold text-danger">{allLoans.length}</span>
</li>
<li className="list-group-item fw-bold">
Total Amount:<span className="fw-bold text-danger">{totalLoan.toFixed(2)}</span>{" "}
</li>
</ul>
</div>
</div>
<div className="section p-5 pagination col-12">
<button className="page-link" onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{"<<"}
</button>{" "}
<button className="page-link" onClick={() => previousPage()} disabled={!canPreviousPage}>
{"<"}
</button>{" "}
<button className="page-link" onClick={() => nextPage()} disabled={!canNextPage}>
{">"}
</button>{" "}
<button className="page-link" onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{">>"}
</button>{" "}
<span className="page-link">
Page{" "}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{" "}
</span>
<span className="page-link">
| Go to page:{" "}
<input
type="number"
value={pageIndex + 1}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}}
style={{ width: "100px" }}
/>
</span>{" "}
<select
className="page-link"
value={pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[20, 50, 100, 200, 500].map((pageSize) => (
<option key={pageSize} value={pageSize} className="page-link">
Show {pageSize}
</option>
))}
</select>
</div>
{/* Go Back */}
<div className="row ">
<div className="col ">
<div className="text-center summary pb-3">
<button className="btn btn-outline-primary mb-0" onClick={goBack}>
<i className="bi bi-skip-backward"></i> Go Back
</button>
</div>
</div>
</div>
<div className="row">
<div className="col">
<Footer />
</div>
</div>
</div>
</>
);
};
export default Allloans;
This is how my page looks:
I can delete each row successfully. The problem is that it deletes when I click on any part of the row. But, I want only the button to be clickable not the whole row. I mean, when I click the delete button only, it should delete.

First, remove the onClick={() => handleClick(row.original.id)} from your row td tag so it become as follows
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>
{cell.render("Cell")}
</td>
);
})}
next, move your on-click handler to the top of the table instance creation
...
const handleClick = (id) => {
dispatch(deleteById(id));
alert("Deleted Successfully.");
console.log(id);
};
const tableInstance = useTable(
{
...
}
);
then, remove the last two columns' definitions (Edit & Delete def) from COLUMNS_ALLLOAN and insert those col definitions into useTable and finally add the onClick event listener to the delete button.
const tableInstance = useTable(
{
columns,
data: allLoans,
initialState: { pageSize: 30 },
},
useGlobalFilter,
useSortBy,
usePagination,
// create Edit and Delete col definition by pushing the two into visibleColumns
(hooks) => {
hooks.visibleColumns.push((col) => [
...col,
{
Header: "Edit",
id: "editBtn",
Cell: ({ row }) => <button className="btn btn-primary">Edit</button>,
},
{
Header: "Delete",
id: "deleteBtn",
Cell: ({ row }) => <button onClick={() => handleClick(row.original.id)} className="btn btn-danger">X</button>,
},
]);
}
);
Here is the minimal example:

Related

React-table: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate

I am using React-table for one of my projects. I implemented the row selection as mentioned in the docs.
below is my table.js
import React, { useEffect, useMemo } from 'react'
import { useTable, usePagination, useRowSelect } from 'react-table';
import {Button, Dropdown, DropdownButton, Form} from 'react-bootstrap';
import BTable from 'react-bootstrap/Table';
export function Table({ columns, data, fetchData, noDataMessage, pageCount: controlledPageCount, loading, rowSelectionEnabled, getSelectedRows }) {
const memoizedColumns = useMemo(() => columns, [columns]);
const memoizedData = useMemo(() => data, [data]);
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
selectedFlatRows,
isAllRowsSelected,
state: { pageIndex, pageSize, selectedRowIds },
} = useTable({
columns: memoizedColumns,
data: memoizedData,
noDataMessage,
initialState: { pageIndex: 0, pageSize: 15 },
manualPagination: true,
pageCount: controlledPageCount,
},usePagination, useRowSelect,
hooks => {
rowSelectionEnabled && hooks.visibleColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
}
)
const setSize = (selectedVal) => {
setPageSize(selectedVal);
}
// const fetchDataDebounced = useAsyncDebounce(fetchData, 100);
React.useEffect(() => {
data.length > 0 && fetchData && fetchData({ pageIndex, pageSize })
}, [fetchData, pageIndex, pageSize])
// React.useEffect(() => {
// data.length === 0 && gotoPage(0)
// }, [data])
// Render the UI for your table
return (
<>
<BTable striped bordered loading={true} minRows={0} className='border-radius-important' {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.length > 0 ? (page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})) : <tr style={{height: '350px'}}><td colSpan={10} style={{verticalAlign: 'middle'}}><NoDataComponent message={noDataMessage}/></td></tr>}
</tbody>
</BTable>
{ pageCount > 1 ? (<div className="pagination">
<div style={{width: '100%', paddingTop: '15px'}}>
<div style={{display: 'flex', float: 'right'}}>
<div style={{display: 'block'}}>
<div>
<Button variant='outline-primary' onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</Button>{' '}
<Button variant='outline-primary' onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</Button>{' '}
<Button variant='outline-primary' onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</Button>{' '}
<Button variant='outline-primary' onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</Button>{' '}
</div>
<div>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</div>
</div>
{/* <div>
| Go to page:{' '}
<input
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
style={{ width: '100px' }}
/>
</div>{' '} */}
</div>
<DropdownButton
style={{float: 'left'}}
title={pageSize}
onSelect={setSize}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<Dropdown.Item eventKey={pageSize}>
{pageSize}
</Dropdown.Item>
))}
</DropdownButton>
</div>
</div>) : null }
{getSelectedRows && getSelectedRows(selectedRowIds, selectedFlatRows, isAllRowsSelected)}
</>
)
}
const NoDataComponent = props => (
// <NoData noDataTitle="This is the dynamic title" {...props} />
<div style={{width: '100%', height: '100%', textAlign: 'center', fontWeight: '700', fontSize: 'large'}}>{props.message}</div>
);
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef()
const resolvedRef = ref || defaultRef
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<Form.Check type="checkbox" ref={resolvedRef} {...rest} />
</>
)
}
)
and the following is the code where i am using this table
getSelectedRows = (rowIds, rowData, isAllRowsSelected) => {
this.setState({selectedData: rowData});
}
<Table columns={this.state.columns} data={this.state.data} rowSelectionEnabled={true} noDataMessage='There is no data to display' getSelectedRows={this.getSelectedRows} fetchData={this.fetchData} pageCount={this.state.count}></Table>
So whenever the checkbox is selected, following line gets triggered in table.js:
{getSelectedRows && getSelectedRows(selectedRowIds, selectedFlatRows, isAllRowsSelected)}
and getSelectedRows function gets called in my component.
But after that page crashes with the error:
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate
I read somewhere that memoizing data and columns will fix the issue as it is going into loop rendering again and again. So I memoized data and columns at the start of table.js file. But still the issue is there.
Can someone please help on this. Thanks in advance!

React-Table resetting to page 1 when I add data

I have a react table with pages that works with me adding new data to the collection however when ever data is added it always resets the current page to 0. Is there some way to save the current state of what page is currently selected? I cant figure out based of this code I have from a fellow what I need to change in order for this to not keep resetting the page index.
My table code looks like this
function Table({ columns, data }) {
const filterTypes = React.useMemo(
() => ({
// Add a new fuzzyTextFilterFn filter type.
fuzzyText: fuzzyTextFilterFn,
// Or, override the default text filter to use
// "startWith"
text: (rows, id, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue !== undefined
? String(rowValue)
.toLowerCase()
.startsWith(String(filterValue).toLowerCase())
: true
})
},
}),
[]
)
const defaultColumn = React.useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
state,
visibleColumns,
preGlobalFilteredRows,
setGlobalFilter,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
selectedPage,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
defaultColumn, // Be sure to pass the defaultColumn option
filterTypes,
initialState: { pageIndex: 0}
},
useFilters, // useFilters!
useGlobalFilter, // useGlobalFilter!
usePagination
)
// We don't want to render all of the rows for this example, so cap
// it for this use case
//const firstPageRows = rows.slice(0, 10)
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
{/* Render the columns filter UI */}
<div>{column.canFilter ? column.render('Filter') : null}</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<br />
{/*<div>Showing the first 20 results of {rows.length} rows</div>*/}
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</button>{' '}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</button>{' '}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</button>{' '}
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</button>{' '}
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</span>
<span>
| Go to page:{' '}
<input
type="number"
defaultValue={pageIndex}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
style={{ width: '100px' }}
/>
</span>{' '}
<select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value))
}}
>
{[10, 20, 30, 40].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</>
)
}```
You might not need to save the current state of what page is currently selected. All you need to do is set autoselect option on your table to false.
Your code should look like this
function Table({ columns, data }) {
const filterTypes = React.useMemo(
() => ({
// Add a new fuzzyTextFilterFn filter type.
fuzzyText: fuzzyTextFilterFn,
// Or, override the default text filter to use
// "startWith"
text: (rows, id, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue !== undefined
? String(rowValue)
.toLowerCase()
.startsWith(String(filterValue).toLowerCase())
: true
})
},
}),
[]
)
const defaultColumn = React.useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
state,
visibleColumns,
preGlobalFilteredRows,
setGlobalFilter,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
selectedPage,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
defaultColumn, // Be sure to pass the defaultColumn option
filterTypes,
initialState: { pageIndex: 0},
autoResetPage: false, //this change should be made
},
useFilters, // useFilters!
useGlobalFilter, // useGlobalFilter!
usePagination
)
// We don't want to render all of the rows for this example, so cap
// it for this use case
//const firstPageRows = rows.slice(0, 10)
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
{/* Render the columns filter UI */}
<div>{column.canFilter ? column.render('Filter') : null}</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<br />
{/*<div>Showing the first 20 results of {rows.length} rows</div>*/}
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</button>{' '}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</button>{' '}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</button>{' '}
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</button>{' '}
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</span>
<span>
| Go to page:{' '}
<input
type="number"
defaultValue={pageIndex}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
style={{ width: '100px' }}
/>
</span>{' '}
<select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value))
}}
>
{[10, 20, 30, 40].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</>
)}
The answer is found on this page of the docs

React-table global filter Regex

Having trouble getting my GlobalFilter to update the table when using Regex to search for multiple results in a column.
export const Table = ({ data, columns }) => {
const filterTypes = useMemo(
() => ({
// Override the default text filter to use
// "startWith"
text: (rows, id, filterValue) => {
return rows.filter((row) => {
const rowValue = row.values[id];
const isRegexMatch = () => {
try {
return RegExp(filterValue).test(String(rowValue));
} catch (err) {
return false;
}
};
return rowValue !== undefined
? String(rowValue)
.toLowerCase()
.startsWith(String(filterValue).toLowerCase()) || isRegexMatch()
: true;
});
},
}),
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
preGlobalFilteredRows,
setGlobalFilter,
state,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
filterTypes,
},
useFilters,
useGlobalFilter,
useSortBy,
usePagination
);
return (
<div className="col-12">
<div className="table-responsive mb-5">
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
<table {...getTableProps()} className="table">
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render('Header')}
<span>
{column.isSorted ? (
column.isSortedDesc ? (
<ChevronDown baseLayer="icon" />
) : (
<ChevronUp baseLayer="icon" />
)
) : (
''
)}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()} key={i}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
<div className="pagination mt-3">
<button
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
className="btn btn-sm btn-link"
>
{'<<'}
</button>{' '}
<button
onClick={() => previousPage()}
disabled={!canPreviousPage}
className="btn btn-sm btn-link"
>
{'<'}
</button>{' '}
<button
onClick={() => nextPage()}
disabled={!canNextPage}
className="btn btn-sm btn-link"
>
{'>'}
</button>{' '}
<button
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
className="btn btn-sm btn-link"
>
{'>'}
</button>{' '}
<span className="mt-2 text-muted">
<small>
Page {pageIndex + 1} of {pageOptions.length}{' '}
</small>
</span>
<span className="mt-2 ms-1 me-1 text-muted">
<small> | Go to page:</small>
</span>
<span className="me-1">
<input
type="number"
className="form-control"
defaultValue={pageIndex + 1}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}}
style={{ width: '80px' }}
/>
</span>
<select
value={pageSize}
style={{ width: '190px' }}
className="form-control"
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize} per page
</option>
))}
<option key={data.length} value={data.length}>
Show All
</option>
</select>
</div>
</div>
</div>
);
};
I only had success so far in the console with this function being able to filter the results, but so far no luck with the react-table package.
function regexFilter(rows, ids, filterValue) {
rows = rows.filter((row) => {
return ids.some((id) => {
const rowValue = row.values[id];
const isRegexMatch = () => {
try {
return RegExp(filterValue).test(String(rowValue));
} catch (err) {
return false;
}
};
return (
String(rowValue)
.toLowerCase()
.includes(String(filterValue).toLowerCase()) || isRegexMatch()
);
});
});
return rows;
}
What am I not doing correctly or mis-interpreting from the documentation on filterTypes?

How to add data into an array using inputs in reactjs?

I am new to react and I am trying to build a todo app which basically can execute the CRUD operation. I am able to update and delete as of now. But not sure how to create an object and save it into the array.
When i click on edit or add task button a modal pop up and i am trying to enter the title and description value there.
This is my Index.js file
import React, {Component} from 'react';
import { Button, Modal } from 'reactstrap';
import Modals from './Modals'
const todoItems = [
{
id: 1,
title: "Go to Market",
description: "Buy ingredients to prepare dinner",
completed: true
},
{
id: 2,
title: "Study",
description: "Read Algebra and History textbook for upcoming test",
completed: false
},
{
id: 3,
title: "Sally's books",
description: "Go to library to rent sally's books",
completed: true
},
{
id: 4,
title: "Article",
description: "Write article on how to use django with react",
completed: false
}
];
class Index extends Component {
state = {
modal: false,
items: todoItems,
selectedItem: null,
selectedIndex: -1,
}
toggle = (item, index) => {
if (item) {
this.setState({ selectedItem: item, selectedIndex: index })
}
this.setState({ modal: !this.state.modal });
};
handleChange = () => {
let oldState = this.state.items;
this.setState({ items: oldState })
}
onDelete = (item) => {
const newData = this.state.items.filter(i => i.title !== item.title)
this.setState({ items: newData })
}
render() {
return (
<>
<h1 className="p-3">TODO APP</h1>
<div style={{ backgroundColor: "white", padding: "50px", color: "black"}} className="container">
<div className="row">
<button className="btn btn-primary" onClick={() => this.toggle()}>Add task</button>
</div>
<div className="row my-5">
<Button color="danger mr-5">Incomplete</Button>
<Button color="success">Complete</Button>
<Modals index={this.state.selectedIndex} onDelete={this.onDelete} item={this.state.selectedItem} handleChange={this.handleChange} modal={this.state.modal} toggle={this.toggle} />
</div>
<hr/>
{this.state.items.map((item, index) => {
return(
<div key={item.id}>
<div className="row">
<p style={{ textAlign: "left" }}>{item.title}</p>
<Button onClick={() => this.toggle(item, index)} className="mr-0 ml-auto" color="info">Edit</Button>
<Button onClick={() => this.onDelete(item)} className="ml-5" color="warning">Delete</Button>
</div>
<hr/>
</div>
)
})}
</div>
</>
);
}
}
export default Index;
This is my modal.js file
import React, { useState, useEffect } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
function Modals(props) {
const {
className,
buttonLabel,
handleChange,
item,
index,
toggle,
} = props;
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
useEffect(() => {
if (item && item.title){
setTitle(item.title)
setDescription(item.description)
}
}, [item])
const setValues = () => {
handleChange({ title: title, description: description });
props.toggle();
push({
})
}
return (
<div>
<Modal isOpen={props.modal} className={className} style={{ color: "black"}}>
<ModalHeader >Todo Item</ModalHeader>
<ModalBody>
<div className="container-fluid">
<div className="row mb-3">
<div className="col-12">
<p className="mb-0">Title</p>
</div>
<div className="col-12">
<input onChange={(e) => setTitle(e.target.value)} value={title} className="w-100" type="text" placeholder="Enter title"/>
</div>
</div>
<div className="row mb-3">
<div className="col-12">
<p className="mb-0">Description</p>
</div>
<div className="col-12">
<input type="text" onChange={(e) => setDescription(e.target.value)} value={description} className="w-100" placeholder="Enter Description"/>
</div>
</div>
<div className="row">
<div className="col-12">
<input type="checkbox"/>
<span className="ml-2"> Completed </span>
</div>
</div>
</div>
</ModalBody>
<ModalFooter>
<Button onClick={() => setValues()} color="success">Submit</Button>
<Button onClick={props.toggle} color="secondary">Cancel</Button>
</ModalFooter>
</Modal>
</div>
)
}
export default Modals;
Thanks in advance!!
One way would be to just create a method in index.js
addItem = (item) =>{
this.setState({items: [...this.state.items, item]})
}
and then just pass it as a prop to your Modal and call it in setValues,
const setValues = () => {
handleChange({ title: title, description: description });
props.toggle();
props.addItem({ title: title, description: description, //etc})
}

React table row selection

I've followed below link and tried to construct a table grid which includes row selection.
https://codesandbox.io/embed/github/tannerlinsley/react-table/tree/master/examples/row-selection
But for some reason it's not working. It's allowing me to select any two rows. When I select 3rd row the previous selection isn't remembered.
Here is the code snippet.
import React, { useState, useEffect, useRef } from "react";
import { useQuery } from "#apollo/react-hooks";
import { ContentWrapper } from "#nextaction/components";
import { useTable, useRowSelect, usePagination } from "react-table";
import $ from "jquery";
import { Row, Col, Button, Badge } from "reactstrap";
import FETCH_XXXXX_QUERY from "../queries/FetchXXXXXQuery";
import { Link } from "react-router-dom";
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef();
const resolvedRef = ref || defaultRef;
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate;
}, [resolvedRef, indeterminate]);
return (
<>
<input type="checkbox" ref={resolvedRef} {...rest} />
</>
);
}
);
function XxxxxxGrid({ columns, data, prospectData }) {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
selectedFlatRows,
state: { selectedRowIds },
} = useTable(
{
columns,
data,
prospectData,
},
useRowSelect,
(hooks) => {
hooks.visibleColumns.push((columns) => [
// Let's make a column for selection
{
id: "selection",
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
]);
}
);
// Render the UI for your table
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>{column.render("Header")}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.slice(0, 10).map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return <td {...cell.getCellProps()}>{cell.render("Cell")}</td>;
})}
</tr>
);
})}
</tbody>
</table>
);
}
const Xxxxxxxx = ({ actions, history }) => {
const { data, loading, error } = useQuery(QUERY);
const gridData = React.useMemo(() => (data ? data.xxxxx.data : []), [data]);
const [activeTab, setActiveTab] = useState("ALL");
const columns = React.useMemo(
() => [
{
Header: "Name",
accessor: "contactName",
Cell: function (props) {
return (
<span>
<b>
<Link to={"/xxxxx/" + props.row.original.id}>
{props.value}
</Link>
</b>
<br></br>
<span>{props.row.original.title}</span>
<br></br>
<Link to={"/xxxxx/" + props.row.original.id}>
{props.row.original.accountName}
</Link>
</span>
);
},
},
{
Header: "Cadence",
accessor: "accountName",
Cell: function (props) {
return (
<span>
<b>
<Link to={"/xxxxxxxx/" + cadence.id}>{props.value}</Link>
</b>
</span>
);
},
},
{
Header: "Tags",
accessor: "tag",
Cell: function (props) {
return (
<Badge color="secondary" pill>
{props.value}
</Badge>
);
},
},
{
Header: "C Outcome",
accessor: "phone",
},
{
Header: "E Outcome",
accessor: "title",
},
{
Header: "Last Contact",
accessor: "createdDate",
},
],
[]
);
const XxxxxxGrid = React.useMemo(
() => (
<XxxxxxGrid
columns={columns}
data={gridData}
prospectData={prospectData}
/>
),
[gridData]
);
return (
<ContentWrapper>
<div className="content-heading pb-0">
<div>
<em className="fa fa-user fa-lg"></em> Prospects
</div>
<div className="ml-auto">
<ul className="nav nav-tabs">
<li className="nav-item">
<a
href="#"
className={
"nav-link text-center" +
(activeTab === "xxxx" ? " active" : "")
}
>
<h4 className="text-primary">1522</h4>
<h6>xxx</h6>
</a>
</li>
<li className="nav-item">
<a
href="#"
className={
"nav-link text-center" +
(activeTab === "xxxx" ? " active" : "")
}
>
<h4 className="text-primary">1522</h4>
<h6>xxxx</h6>
</a>
</li>
<li className="nav-item">
<a
href="#"
className={
"nav-link text-center" +
(activeTab === "xxxx" ? " active" : "")
}
>
<h4 className="text-primary">1522</h4>
<h6>xxx</h6>
</a>
</li>
<li className="nav-item">
<a
href="#"
className={
"nav-link text-center" +
(activeTab === "xxxxxx" ? " active" : "")
}
>
<h4 className="text-primary">1522</h4>
<h6>xxxxx</h6>
</a>
</li>
</ul>
</div>
</div>
<Row className="mb-3">
<Col sm={4}>
<div className="input-group pl-0">
<input
type="text"
className="form-control"
placeholder="Search"
aria-label="Search"
aria-describedby="button-addon2"
/>
<div className="input-group-append">
<Button
color="outline-secondary"
type="button"
id="button-addon2"
>
<i className="fa fa-search"></i>
</Button>
</div>
</div>
</Col>
</Row>
<Row className="border-bottom border-top">
<div className="ml-auto">
<Button color="outline">
<em className="fas fa-file-csv text-primary"></em> Import CSV
</Button>
|
<Button color="outline">
<em className="fa fa-plus text-primary"></em> Add
</Button>
</div>
</Row>
<Row>{!loading && XxxxxxGrid}</Row>
</ContentWrapper>
);
};
export default Xxxxxxxx;
Something similar happened to me,
in my case the bug was generated due to a conflict with the StrictMode generated by default in index.js.
Try to Delete it
ReactDOM.render (
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById ('root')
the Index should look like this:
ReactDOM.render (
<App />,
document.getElementById ('root')

Resources