next prop not working in react-infinite-scroll-component - reactjs

The infinite scroll component is in a table and its inside a scrollable page. i tried giving
id="scrollableDiv" to every div in the page and also <html> in index.html still no use. when i remove the scrollableTarget="scrollableDiv" the fetchdata works untill the parent scroll bar in the bottom. after that fetchData function not working. when i forcefully scroll the parent scroll fetchdata works.
But i want it to work on scrolling the table. Not when scrolling the parent(i mean the whole page), anyone tell me where should i assingn id="scrollableDiv". There is no div with height specified
Here is the code,
const fetchMoreData = () => {
console.log("new more data");
const temp = [...ingestStats];
setTimeout(() => {
setIngestStats((prev) => prev.concat(temp));
}, 1500);};
<div className="row">
<div className="col-xl-12">
<div className="card dashboard-table">
{/* /.card-header */}
<div className="card-body p-0" id="collapse1">
<InfiniteScroll
dataLength={ingestStats.length}
next={fetchMoreData}
hasMore={ingestStats.length < 40 ? true : false}
loader={
<p style={{ textAlign: "center" }}>
<b>Loading...</b>
</p>
}
endMessage={
<p style={{ textAlign: "center" }}>
<b>Yay! You have seen it all</b>
</p>
}
scrollableTarget="scrollableDiv"
>
<table className="table table-hover table-borderless text-center table-sm table-responsive">
<thead>
<tr>
<th>Activity</th>
<th>
Time Stamp{" "}
<span href="#0">
<i className="fas fa-angle-down" />
</span>
</th>
<th>
Status{" "}
<span href="#0">
<i className="fas fa-angle-down" />
</span>
</th>
</tr>
</thead>
<tbody>
{ingestStats &&
ingestStats.map((item, index) => (
<tr key={`${item.time}-${index}`}>
<td>{item.activity}</td>
<td>{item.time}</td>
<td>
{item.isActive ? (
<span className="status-success">
Success
</span>
) : (
<span className="status-failed">
Success
</span>
)}
</td>
</tr>
))}
</tbody>
</table>
</InfiniteScroll>
</div>
{/* /.card-body */}
</div>
</div>
</div>

I was encountering a similar problem where the infinitescroll element would take the whole window in order to scroll... However, there is a small fix for this. You actually just need to add 'height' to the InfiniteScroll element and all your problems will be gone. That is the reason why it won't trigger your fetch data. See down for an example:
const [fetchIsLoading, setFetchIsLoading] = useState(false);
const [contacts, setContacts] = useState([]);
const loadMoreData = () => {
if (fetchIsLoading) {
return;
}
setFetchIsLoading(true);
fetch('https://randomuser.me/api/?results=10&inc=name,gender,email,nat,picture&noinfo')
.then((res) => res.json())
.then((body) => {
setContacts([...contacts, ...body.results]);
setFetchIsLoading(false);
})
.catch(() => {
setFetchIsLoading(false);
});
};
useEffect(() => {
loadMoreData();
}, []);
<div // < ------------- top level div with id 'scrollableDiv' is not even needed... but it works (if you use it or not)
// id="scrollableDiv"
// style={{height: 400}}
>
<InfiniteScroll style={{
// height: 400 <-------- this does not work!
}}
dataLength={contacts.length}
next={loadMoreData}
hasMore={true}//contacts.length < 15
loader={
<Skeleton
avatar
paragraph={{
rows: 1,
}}
active
/>
}
height={400} // <--------- however, this works through the way this infinite scroll is set up.
endMessage={<Divider plain>It is all, nothing more 🤐</Divider>}
//scrollableTarget="scrollableDiv" <-------- this is not even needed the way this infinite scroll is set up. Even though you point it to the top level div it works either way...
>
<List
dataSource={contacts}
renderItem={(item) => (
<List.Item key={item.email}>
<List.Item.Meta
avatar={<Avatar src={item.picture.large} />}
title={<div style={{ color: '#54BEC6', cursor: 'pointer' }}>{item.name.last}</div>}
description={item.email}
onClick={(event) => onClickContactsTab(event, item.name.last)}
/>
{
// Use this section to put extra information about the user
//<div>Extra info?</div>
}
</List.Item>
)}
/>
</InfiniteScroll>
</div>

Related

React Draft Wysiwyg always getting Cannot read properties of undefined (reading 'createWithContent') error

My problem is not able render the html code in the editor.
Here is my code for your reference :
const divRef = useRef(null);
const [contentState, setContentState] = useState(); // ContentState JSON
const blocksFromHTML = convertFromHTML(divRef.current.innerHTML);
const state = ContentState.createFromBlockArray(
blocksFromHTML.contentBlocks,
blocksFromHTML.entityMap
);
this.state = {
editorState: EditorState.createWithContent(state)
}
I want to render the table data on the editor. Here is my html code for your reference.
<div className='row' ref={divRef}>
<div className='col-lg-12'>
<table id="checklist">
<tr>
<th>Task List</th>
<th>Assignee</th>
<th>Status</th>
<th>Comments</th>
</tr>
{
ViewChecklistItem.map((row, index) => (
<tr key={row.TaskId}>
<td width="45%">{row.TaskName}</td>
<td>{row.AssigneeName}</td>
<td>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="demo-controlled-open-select-label">Status</InputLabel>
<Select
className={"copy "+(row.AllowStatusChange === 'Y' ? 'allowed' : 'not-allowed')}
labelId="demo-controlled-open-select-label"
id="demo-controlled-open-select"
open={open[index]}
onClose={() => { handleClose(index) }}
onOpen={() => { handleOpen(index) }}
value={status[index] || row.StatusId}
label="Status"
onChange={(event, newValue) => {
setStatusId(event.target.value);
setTaskId(row.TaskId);
setStatusPopup(true);
}}
>
{StatusList?.map(status => {
return (
<MenuItem value={status.StatusId}>{status.Status}</MenuItem>
);
})}
</Select>
</FormControl>
</td>
<td><a href="javascript:;" onClick={() => viewLogs(row.TaskId, row.TaskName, row.AssigneeName)} className='view-log'><img src={view_log} /> View Log</a></td>
</tr>
))
}
</table>
</div>
</div>
But am getting the output in console.log(divRef.current.innerHTML);
Please help me out. where I missed.
I have upated Editior code below:
<Editor
editorState={editorState}
defaultContentState={contentState}
onContentStateChange={setContentState}
wrapperClassName="wrapper-class"
editorClassName="editor-class"
toolbarClassName="toolbar-class"
/>

How to handle delete popup confirmation for an api in reactjs

Could anyone help me out here please, all I'm trying to do here is to show popup modal confirmation for delete action, but every time I clicked on **Yes **btn to confirm my delete action the last product on the list always get deleted instead. I need help from anyone please?
Here is my code for handling the delete popup
```
//OPEN DELETE MODALS
const [openDeleteModal, isOpenDeleteModal] = useState(false);
const closeDeleteModal = () => {
isOpenDeleteModal(false);
document.body.style.overflow = "unset";
};
const showDeleteModal = () => {
isOpenDeleteModal(true);
};
```
and here is the api
```
//DELETE PRODUCT
const deleteHandler = async (product) => {
try {
await axios.delete(`/api/products/${product._id}`, {
headers: { Authorization: `Bearer ${userInfo.token}` },
});
toast.success("product deleted successfully", {
position: "bottom-center",
});
dispatch({ type: "DELETE_SUCCESS" });
} catch (err) {
toast.error(getError(err), { position: "bottom-center" });
dispatch({ type: "DELETE_FAIL" });
}
};
```
down here is my modal for confirmation
```
{/* MODAL */}
{openDeleteModal && (
<div className="delete-modal">
<div className="delete-modal-box">
<div className="delete-modal-content">
<p className="delete-modal-content-p">
Are you sure to delete this product?
</p>
<div className="delete-modal-btn">
<button
onClick={closeDeleteModal}
className="delete-modal-btn-close"
>
Close
</button>
<button
onClick={() => {
deleteHandler(product);
closeDeleteModal();
}}
className="delete-modal-btn-yes"
>
{" "}
Yes
</button>
</div>
</div>
</div>
</div>
)}
```
All I'm trying to do is to be able to delete any product from the list not the last product every time.
here is the entirety of my productList map looks like
{products?.map((product, index) => (
<tr className="product-item-list" key={index}>
<tr>
<td className="product-item-id">{product._id}</td>
<td className="product-item-name">
{product.name}
</td>
<td className="product-item-price">
£{product.price}
</td>
<td className="product-item-category">
{product.category?.map((cat, index) => (
<span key={index}>{cat}</span>
))}
</td>
<td className="product-item-size">
{product.size?.map((s, index) => (
<span key={index}>{s} </span>
))}
</td>
<td className="product-btn-view">
<button
className="product-btn"
onClick={() =>
navigate(`/admin/productedit/${product._id}`)
}
>
Edit
</button>
<DeleteOutline
className="product-delete"
onClick={showDeleteModal}
/>
{/* MODAL */}
{openDeleteModal && (
<div className="delete-modal">
<div className="delete-modal-box">
<div className="delete-modal-content">
<p className="delete-modal-content-p">
Are you sure to delete this product?
</p>
<div className="delete-modal-btn">
<button
onClick={closeDeleteModal}
className="delete-modal-btn-close"
>
Close
</button>
<button
onClick={() => {
deleteHandler(product);
closeDeleteModal();
}}
className="delete-modal-btn-yes"
>
{" "}
Yes
</button>
</div>
</div>
</div>
</div>
)}
</td>
</tr>
<tr></tr>
</tr>
))}
I guess it happens because all of your modals open when you call showDeleteModal
And the last one is on the top, so when you click to delete the last closure works. Maybe its nessesary to pass id of product into the openDeleteModal. And than check if product.id equals to openDeleteModal.
Can you print to console the product.id when you click on the "Delete" button and check is it the correct id of the clicked product?

how to scroll specific column to second column using react useRef?

I have a table and first column position is sticky. The first row is the date of the month. and the first column is student information. I want a button onClick action is scroll the specific column(today column) to the position next to the first column. How can I do that?
Any suggestion is appreciated.
After I assign ref to the today's column, The scrollIntoView() function work. The column I want to show will under the sticky column. So I want to use scrollTo() function to provide accurate position. The issue is that scrollTo() doesn't work. Which element should I assign useRef. table, tableRow or tableData(tableHead)?
type ListProps = {
AppStore: AppStore;
TaskScheduleStore: TaskScheduleStore;
EmployeeShiftStore: EmployeeShiftStore;
BusRouteStore: BusRouteStore;
};
const List: React.FC<ListProps> = ({
AppStore,
TaskScheduleStore,
EmployeeShiftStore,
BusRouteStore,
}) => {
const myRef = useRef<HTMLTableElement>(null);
return (
<Container>
<Card>
<div className='flex flex-row justify-between items-center'>
<div className='flex flex-row items-center'>
{format(currentDate, 'yyyy年M月')}
<button
onClick={() => {
// here is the button I want to scroll the column to specific position.
var table = document.getElementById(
'employeeShiftTable'
) as HTMLTableElement;
console.log(table?.scrollWidth)
// here can print the table width.
if (myRef.current !== null) {
myRef.current.scrollBy({
top: 100,
left: 400,
behavior: 'smooth',
});
}
}}
>
<span>Today</span>
</button>
</div>
</div>
<div>
<table id='employeeShiftTable' ref={myRef}>
<thead>
<tr>
<th>
corner
</th>
{Array(getDaysInMonth(currentDate))
.fill(currentDate)
.map((date, index) => {
return (
<th>
<div>
{index + 1}
</div>
</th>
);
})}
</tr>
</thead>
<tbody>
{employeeShifts.map((data, rowIndex) => (
<tr>
<th className='headcol'>
<div>
{rowIndex}
</div>
<div className='flex flex-row align-items-center jobTitle'>
00012 Name
</div>
</th>
{Array(getDaysInMonth(currentDate))
.fill(1)
.map((daea, columnIndex) => (
<td>
<div style={{ padding: '12px' }}>
test
</div>
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</Card>
</Container>
);
};
export default inject(
({ AppStore, TaskScheduleStore, EmployeeShiftStore, BusRouteStore }) => ({
AppStore,
TaskScheduleStore,
EmployeeShiftStore,
BusRouteStore,
})
)(observer(List));
an easy solution is to use an a tag with href="#id" and on the element that you want to scroll give it the same id that you mentioned in the href

ReactJs unit testing with jest and enzyme

I have the following return method in one of my components (AreaCodesTable):
<>
<Button
id="create-email-template"
className="p-button-rounded p-button-text p-button-icon-only blubicon-plus"
onClick={() => this.toggleCreateAreaCodeModal()}
></Button>
<Tooltip target={'#create-email-template'} content={this.props.t('common.areaCode')} position={'left'} />
<DataTable dataKey="id" id="area-codes-table" value={this.props.rootStore.areaCodeStore.areaCodes}>
<Column key="title" field="title" header={this.props.t('areaCodes.shared.title')} style={{ width: '11rem' }} />
<Column
key="description"
field="description"
header={this.props.t('areaCodes.shared.description')}
style={{ width: '11rem' }}
/>
<Column
body={this.showButtons}
headerStyle={{ width: '10%', minWidth: '8rem' }}
bodyStyle={{ textAlign: 'center' }}
></Column>
</DataTable>
<DeleteModal
deleteMode={this.state.showDeleteModal}
confirmDeleteTemplate={this.confirmDeletion}
discardDeleteTemplate={this.toggleDeleteAreaCodeModal}
header={this.props.t('areaCodes.delete.header')}
/>
{this.state.showEditModal && (
<EditAreaCodeModal
selectedAreaCode={this.state.selectedAreaCode}
confirmEdit={this.confirmEdit}
toggleEditAreaCodeModal={this.toggleEditAreaCodeModal}
visible={this.state.showEditModal}
rootStore={this.props.rootStore}
/>
)}
{this.state.showCreateModal && (
<CreateAreaCodeModal
rootStore={this.props.rootStore}
toggleCreateAreaCode={this.toggleCreateAreaCodeModal}
getAreaCodesRefresh={this.getAreaCodes}
/>
)}
</>
However I can't simulate a click in my unit tests.
describe('area codes table', () => {
const backendBaseUrl = 'http://localhost:8081';
const mockDataProvider = new DataProvider(backendBaseUrl);
const rootStore = new RootStore(mockDataProvider);
const props = {
rootStore: rootStore,
i18n: i18n,
t: t,
};
const initialState = {
showDeleteModal: false,
showEditModal: false,
showCreateModal: false,
selectedAreaCode: null,
};
let reactComponent: ShallowWrapper<IAreaCodesTableProps, IAreaCodesTableState>;
beforeEach(() => {
reactComponent = shallow(<AreaCodesTable {...props} />);
});
afterEach(() => {
reactComponent.unmount();
});
it('should show create modal', () => {
const createButton = reactComponent.find('button');
createButton.simulate('click');
});
});
Either I use reactComponent.find('#create-email-template') or .find('button') I get this error message: Method “simulate” is meant to be run on 1 node. 0 found instead. . For the first one I understand why- because we have to ids create-email-template, but for the second I dont know- I used Button, #button, #Button combinations as well, but didnt work.
This is the result from reactComponent.html():
<button
id="create-email-template"
class="p-button p-component p-button-rounded p-button-text p-button-icon-only blubicon-plus"
>
<span class="p-button-label p-c"> </span>
</button>
<div
id="area-codes-table"
class="p-datatable p-component"
data-scrollselectors=".p-datatable-scrollable-body, .p-datatable-unfrozen-view .p-datatable-scrollable-body"
>
<div class="p-datatable-wrapper">
<table role="grid">
<thead class="p-datatable-thead">
<tr role="row">
<th role="columnheader" class="p-sortable-disabled" style="width:11rem">
<span class="p-column-title"></span>
</th>
<th role="columnheader" class="p-sortable-disabled" style="width:11rem">
<span class="p-column-title"></span>
</th>
<th role="columnheader" class="p-sortable-disabled" style="width:10%;min-width:8rem">
<span class="p-column-title"></span>
</th>
</tr>
</thead>
<tbody class="p-datatable-tbody">
<tr role="row" class="p-datatable-emptymessage">
<td role="cell" colSpan="3">
No records found
</td>
</tr>
</tbody>
</table>
</div>
</div>
Everything is here.

Word is not getting added until the page is refreshed in TableItem component in React

TableItem component added without any data in UI. Could somebody help on this. On refereshing the UI, added data is shown with details in TableItem component.
Table Component Code
import TableItem from "./TableItem";
function Table({ searchWord }) {
const dispatch = useDispatch();
const dictData = useSelector((state) => state.dictionary);
useEffect(() => {
dispatch(getDictionaryAsync());
}, [dispatch]);
return (
<table className="table table-striped">
<thead>
<tr>
<th scope="col">Word</th>
<th scope="col">Description</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{dictData &&
dictData
.filter((e) =>
searchWord === ""
? e
: e.word &&
e.word.toLowerCase().includes(searchWord.toLowerCase())
)
.map((item) => (
<TableItem item={item} key={item.id} searchWord={searchWord} />
))}
</tbody>
</table>
);
}
export default Table;
Below is the TableItem Component Code which i am trying to update,
When i add a word to dictionary it will fetch the details from the server and display it in the React app.
function TableItem({ item }) {
const [modal, setModal] = useState(false);
const openModal = () => {
setModal(true);
};
return (
<>
<tr key={item.id}>
<td style={{ textTransform: "capitalize" }}>{item.word}</td>
<td>
<b style={{ textTransform: "capitalize" }}>
{item.items && item.items[0].category} -{" "}
</b>
{item.items && truncate(item.items[0].definitions[0])}
</td>
<td>
<button className="btn btn-danger btn-sm " onClick={openModal}>
View
</button>
</td>
</tr>
<Modal isOpen={modal} ariaHideApp={true}>
<div className="modal-header">
<h3 className="modal-word-header">
{item.word && item.word.toUpperCase()}
</h3>
<button
className="btn btn-danger btn-sm"
onClick={() => setModal(false)}
>
<i class="fa fa-times" aria-hidden="true"></i>
</button>
</div>
<div className="model-content">
<p>
{item.items &&
item.items.map((e) => {
return (
<>
<i>{e.category}</i>
<ul>
{e.definitions.map((def) => {
return <li>{def}</li>;
})}
</ul>
</>
);
})}
</p>
</div>
</Modal>
</>
);
}
Better add your TableItem component code!
Below code works fine and updated the UI on change in the Data in TableItem,
useEffect(() => {
dispatch(getDictionaryAsync());
}, [dispatch, dictData]); *<--updated code*

Resources