Paginate a mapped array - javascript

I am trying to paginate over an array
I am fairly new to react and don't know where to start
I am trying to paginate this list of events so it only shows 9 events on the page
and when there are more you can click on 2 or 3 etc to see more
and I have no idea how to implement pagination
class EventsList extends PureComponent {
componentWillMount() {
this.props.getAllEvents();
}
getEvent(eventId) {
this.props.getEvent(eventId);
}
addEvent = event => {
this.props.addEvent(event);
};
render() {
const now = Moment();
const { events, authenticated } = this.props;
const eventsList = events.sort((a, b) =>{
return a.id - b.id;
});
if (!authenticated) return <Redirect to="/login" />;
return <div>
<Paper className="styles" elevation={4}>
<h1>Coming Events</h1>
<table>
<thead>
<tr>
<th>Event Name</th>
<th>Starts</th>
<th>Ends</th>
<th>Short description</th>
</tr>
</thead>
<tbody>
{eventsList.map(event => <tr key={event.id}>
<td>
<Link className="link" to={`/events/${event.id}`} onClick={() => this.getEvent(event.id)}>
{event.name}
</Link>
</td>
{now && <td style={{ border: "2px solid black" }}>
{Moment(event.startDate).format("ll")}
</td>}
{now && <td style={{ border: "2px solid black" }}>
{Moment(event.endDate).format("ll")}
</td>}
<td />
<td style={{ border: "2px solid green" }}>
{event.description}
</td>
<td />
</tr>)}
</tbody>
</table>
<br />
<br />
<Link className="link" to={`/addEvent`}>
Add An Event
</Link>
</Paper>
</div>;
}
}
const mapStateToProps = function(state) {
return {
events: state.events,
event: state.event,
authenticated: state.currentUser !== null,
users: state.users === null ? null : state.users
};
};
export default connect(
mapStateToProps,
{
getAllEvents,
getEvent,
addEvent,
getUsers
}
)(EventsList);
I am looking at
http://pagination.js.org
and https://www.npmjs.com/package/react-js-pagination
but I don't get how I should implement it.
If someone can give me some pointers?
or a simple example ?

You are going to need to keep track of a few items. First the total number of events. Second the current page. Third the number of items per page (a constant you want to set).
Then you can do any number of things to your events array to only show those items.
For example, you could use an array slice https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice -- This will give you back a new array with only the items you want.
So to get a second page of items (10 - 19) you would calculate your start and end indexes based on the page number and the number of items per page and then end up with something like.
const numberPerPage = 9;
const startIndex = 10; // Computed based on your numbers
const endIndex = startIndex + numPerPage;
const pagedEvents = eventsList.slice(startIndex, endIndex);
That will give you a list with only the items for that page. Updating the page number will cause the numbers to change and the list to update.

Related

useEffect resets the numStudents state after check out

So I created a app takes attendance of students. but when i try to check out useEffect resets the state of numStudents after update.
the code is :
const Attendance = () => {
// Declare state variables
const [students, setStudents] = useState([]);
const [numStudents, setNumStudents] = useState(0);
// Function to add a student to the attendance list
const addStudent = (rollNumber, name) => {
setStudents(
students.concat({
rollNumber,
name,
checkInTime: new Date().toLocaleString(),
})
);
};
// Function to check a student out
const checkOut = (rollNumber) => {
setStudents(
students.map((student) => {
if (student.rollNumber === rollNumber) {
return { ...student, checkOutTime: new Date().toLocaleString() };
}
return student;
})
);
setNumStudents(students.length-1);
};
// Use effect hook to update the number of students when the 'students' state variable changes
useEffect(() => {
setNumStudents(students.length);
}, [students]);
return (
<div>
{/* Form to input student roll number and name */}
<form
onSubmit={(e) => {
e.preventDefault();
addStudent(e.target.rollNumber.value, e.target.name.value);
e.target.rollNumber.value = "";
e.target.name.value = "";
}}
>
<div className="container">
<h1>Student Attendance</h1>
<label>
Roll Number
<input type="number" name="rollNumber" />
</label>
<br />
<label>
Name
<input type="text" name="name" />
</label>
<br />
<button type="submit">Check In</button>
</div>
</form>
{/* Display number of students present */}
<p>There are currently {numStudents} students in the school.</p>
{/* Table to display list of students and their check in/out times */}
<br />
<table className="fl-table">
<thead>
<tr>
<th>Roll Number</th>
<th>Name</th>
<th>Check In Time</th>
<th>Check Out Time</th>
</tr>
</thead>
<tbody>
{students.map((student) => (
<tr key={student.rollNumber}>
<td>{student.rollNumber}</td>
<td>{student.name}</td>
<td>{student.checkInTime.toString()}</td>
<td>
{student.checkOutTime ? (student.checkOutTime.toString()) : (
<button
key={student.rollNumber} onClick={() => checkOut(student.rollNumber)}>
Check Out
</button>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default Attendance;
I tried using setNumStudents(students.length-1) in checkOut function but it updates and then useEffect is called that resets it again . How do i make it not reset ? i am new to react Hooks so plz help!!!
Why do you need an effect here at all? I mean you already updating numStudents in checkout handler.
Ideally useEffect should be used to hook up your app to external library or make a http request(like fetching students from server)
When you checkout student you responding to event fired by user, and should update state variables in event handler.
// Function to add a student to the attendance list
const addStudent = (rollNumber, name) => {
setStudents(
students.concat({
rollNumber,
name,
checkInTime: new Date().toLocaleString(),
})
);
setNumStudents(numStudents + 1)
};
// Function to check a student out
const checkOut = (rollNumber) => {
setStudents(
students.map((student) => {
if (student.rollNumber === rollNumber) {
return { ...student, checkOutTime: new Date().toLocaleString() };
}
return student;
})
);
setNumStudents(numStudents - 1);
};

Prevent React table from scrolling to top on update

I have a react table that contains information in my Electron application. However, whenever data in the table is updated or a button is clicked, the table scrolls to the top, frustrating users.
Example code is as follows:
const tableContent = listItem.map((item: any, index: number) => {
return (
<Tr key={index.toString()} className="section">
<Td>{item.<item1>}</Td>
<Td>
<Icon
onClick={() => exampleFunction()}
/>
</Td>
</Tr>
);
});
return (
<Div className="round-card page-content-table table-responsive padding-20">
{<Table className="table table-striped">
<Thead>
<Tr>
<Th>TH1</Th>...
<Th>TH2</Th>
</Tr>
</Thead>
{<Tbody>{tableContent}</Tbody>}
</Table>}
</Div>)
How can I avoid these scroll jumps in the element during updates?
Update:
I was able to get the scroll position to save however, when the table updates, the scroll is stuck to the previous point, making it impossible for users to scroll when the table is updating. Any way to avoid this?
const [scrollPostion, setScrollPosition] = useState(
parseInt(localStorage.getItem('scrollPos')) || 0
);
const TableRef = useRef(null);
const scrollEvent = (e) => {
setScrollPosition(e.target.scrollTop);
localStorage.setItem('scrollPos', scrollPostion.toString());
};
React.useEffect(() => {
localStorage.setItem('scrollPos', scrollPostion.toString());
}, [scrollPostion]);
For anyone who runs into this issue in the future, I solved by moving the table into new component and putting it in the div
const myTable = () => {
const tableContent = listItem.map((item: any, index: number) => {
return (
<Tr key={index.toString()} className="section">
<Td>{item.<item1>}</Td>
<Td>
<Icon
onClick={() => exampleFunction()}
/>
</Td>
</Tr>
);
};
return (
<Table className="table table-striped">
<Thead>
<Tr>
<Th>TH1</Th>...
<Th>TH2</Th>
</Tr>
</Thead>
{<Tbody>{tableContent}</Tbody>}
</Table>}
)
}
const pageContent = () = {
return (
<Div className="round-card page-content-table table-responsive padding-20">
<myTable></myTable>
</Div>)
)
}

Unable to filter properly data in react js table based on field?

I have a below problem in which filter is not working properly. As per below code, I have some data which i am displaying in table and i have one status column i.e active or inactive. I wanted to filterout table based on the status active or inactive. So, when I tried to filter based on Active, it is working but not working for Inactive status as table goes empty. And same thing happened when I try with Inactive first then it filter out correctly table but this time not working for active status as table goes empty. So, its not retaining state of original data. Overall I wanted to switch between Active & Inactive status.
import React, { useState } from "react";
const initialData = [
{
id: 1,
name: "Mayank Kumar",
email: "mayankkumar#gmail.com",
status: "Active",
},
{
id: 2,
name: "Jitender Kumar",
email: "jitenderskumar#gmail.com",
status: "Inactive",
},
];
const TableDemo = () => {
const [data, setData] = useState(initialData);
const filterData = (value) => {
const filterData = data.filter((item) => item.status === value);
setData(filterData);
};
return (
<div>
<table>
<thead>
<tr>
<th style={{ textAlign: "center" }}>No.</th>
<th style={{ textAlign: "center" }}>Name</th>
<th style={{ textAlign: "center" }}>Email</th>
<th style={{ textAlign: "center" }}>Status</th>
</tr>
</thead>
<tbody>
{data.map((item, index) => {
return (
<tr key={item.id}>
<th scope="row">{index + 1}</th>
<td>{item.name}</td>
<td>{item.email}</td>
<td>{item.status}</td>
</tr>
);
})}
</tbody>
</table>
<label>Status:</label>
<button onClick={() => filterData("Active")}>Active</button>
<button onClick={() => filterData("Inactive")}>Inactive</button>
</div>
);
};
export default TableDemo;
What happens here is when you filter the first time for "Active", you are setting new items without the ones that are "Inactive" so you basically lose the data that way.
In your case, there's no need to store your data inside the state. A better approach would be to store a filter inside the state and then conditionally calculate the values you need on render.
const [filter, setFilter] = useState('All')
// use filteredData to map and render the items
const filteredData = initialData.filter(item => {
if (filter === 'All') {
return true
}
return item.status === filter
})
// use filterData function to set the filter
const filterData = (value) => {
setFilter(value);
};

how to update integer value imported from a module in react

I'm trying a simple interactive table using react, where the table displays a set of details of Books, namely name, price, and stock. The details of the books are stored in a separate JS fine as a module and imported into the component file. Also 'stock' value is saved as a number type in the module. When I try to add or reduce the 'stock' value by one using a button, it doesn't make any changes to the value count.
Below is my code:
import React, { Component } from 'react';
import bookStock from '../Models/books'
class Books extends Component {
state = {
bookList: bookStock
}
totalCopies(){
let sum = 0
this.state.bookList.forEach(book => (
sum = sum + book.stock
))
return sum;
}
addBookCount = (book) => {
this.setState({book.stock = book.stock + 1})
}
reduceBookCount = book => {
this.setState({book.stock = book.stock - 1})
}
render() {
const {length} = this.state.bookList
return (
<React.Fragment>
<table className="table table-borderless">
<thead>
<tr>
<th>Title</th>
<th>Price</th>
<th>No.of Copies</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.bookList.map(book => (
<tr key = {book.id}>
<td>{book.name}</td>
<td>{book.Price}</td>
<td>{book.stock}</td>
<td><button onClick={() => this.addBookCount(book)} className="btn btn-success btn-sm">ADD</button></td>
<td><button onClick={() => this.reduceBookCount(book)} className="btn btn-danger btn-sm">REDUCE</button></td>
</tr>
))}
</tbody>
</table>
<br/>
<h1>Total No.of Books: {length}</h1>
<h1>Total No.of Copies: {this.totalCopies()}</h1>
</React.Fragment>
);
}
}
export default Books;
How can I increment and decrement the stock value? The totalCopies method is working fine and it displays the total number of copies
Your state has a bookList state that maintains the bookStock.However
In the addBookCount function:
You are trying to update the property book.stock which doesn't exist in your state.
Moreover, this isn't the correct way to update the stock.
First, make a copy of the state in a local variable.
Then, find the book passed as an argument into the function in the local variable (bookList).
Update the stock there.
Now, set the local variable as the new state value.
import React, { Component } from 'react';
import bookStock from '../Models/books'
class Books extends Component {
state = {
bookList: bookStock,
bookcount: 0,
}
totalCopies(){
let sum = 0
this.state.bookList.forEach(book => (
sum = sum + book.stock
))
this.setState({bookcount: sum})
}
addBookCount = (book) => {
this.setState({book.stock = book.stock + 1})
}
reduceBookCount = book => {
this.setState({book.stock = book.stock - 1})
}
render() {
const {length} = this.state.bookList
return (
<React.Fragment>
<table className="table table-borderless">
<thead>
<tr>
<th>Title</th>
<th>Price</th>
<th>No.of Copies</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.bookList.map(book => (
<tr key = {book.id}>
<td>{book.name}</td>
<td>{book.Price}</td>
<td>{book.stock}</td>
<td><button onClick={() => this.addBookCount(book)} className="btn btn-success btn-sm">ADD</button></td>
<td><button onClick={() => this.reduceBookCount(book)} className="btn btn-danger btn-sm">REDUCE</button></td>
</tr>
))}
</tbody>
</table>
<br/>
<h1>Total No.of Books: {length}</h1>
<h1>Total No.of Copies: {this.state.bookcount}</h1>
</React.Fragment>
);
}
}
export default Books;
Can you try this
I have finally found the way. Thanks everyone for responding me
addBookCount = (book) => {
this.state.bookList.filter(b => b.id === book.id).forEach(bk => bk.stock = bk.stock + 1)
this.setState({})
}
reduceBookCount = book => {
this.state.bookList.filter(b => b.id === book.id).forEach(bk => bk.stock = bk.stock - 1)
this.setState({})
}

How can I integrate searching functionality on table?

At the moment, all the available flights that was received from API are successfully loaded on the page. However, I would like to enable the end user to search specific flight, let's say, by flight number and departure date. How can I integrate this searching functionality in the existing codes?
FlightPage.js
render() {
return (
<>
<h2>Flights</h2>
{this.props.loading ? (
<div>Loading...</div>
) : (
<FlightList flights={this.props.flights} />
)}
</>
);
}
}
As you can see the bellow code, I have used table to present the results.I would like to show only one result or blank table when searching is applied. Can you help me to achieve this?
FlightList.js
const FlightList = ({ flights }) => (
<table className="table">
<thead>
<tr>
<th />
<th>Date</th>
<th>Provider</th>
<th>Dest</th>
</tr>
</thead>
<tbody>
{flights.map((f, i) => {
return (
<tr key={i}>
<td>
<input type="checkbox" name="flightListCheckbox" />
</td>
<td>{f.date}</td>
<td>{f.pnr}</td>
<td>{f.flightNumber}</td>
</tr>
);
})}
</tbody>
</table>
);
You could use filter to create a searching functionality like
I would at first add an input where I can insert my filter values
FlightPage.js
handleInput: (event) => {
const { name, value } = event.target
this.setState({ [name]: value })
}
render () {
const { filter } = this.state
return (
<>
<input onChange=(this.handleInput) value={filter} name='filter' />
<FlightList flights={this.props.flights} filterValues={filter} />
</>
)
}
Then I would use my state to filter my Object like
FlightList.js
const FlightList = ({ flights, filterValue }) => {
const filterdFlights = flights.filter(flight => Object.values(flight).includes(filterValue))
return (
<table className="table">
<thead>
<tr>
<th />
<th>Date</th>
<th>Provider</th>
<th>Dest</th>
</tr>
</thead>
<tbody>
{filterdFlights.map((f, i) => {
return (
<tr key={i}>
<td>
<input type="checkbox" name="flightListCheckbox" />
</td>
<td>{f.date}</td>
<td>{f.pnr}</td>
<td>{f.flightNumber}</td>
</tr>
);
})}
</tbody>
</table>
)};
You need an input for search and filter flights by value of input. Try this
class FlightPage extends React.Component {
state = {
keyword: '',
}
...
getFlights = () => {
const { keyword } = this.state
const { flights } = this.props
return flights.filter(flight => flight.name.includes(keyword)) // name or something else
}
onInputChange = e => {
this.setState({ keyword: e.target.value })
}
render () {
return (
<>
<input onChange=(this.onInputChange) value={this.state.keyword} />
<FlightList flights={this.getFlights()} />
</>
)
}
}
You can filter your flights array using flights.filter or sort it using flights.sort.
You could try to use jquery datatable. It adds a lot of funcionality to tables easy to implement.
DataTable doc

Categories

Resources