Issue with leave animation using React-Flip-Move - reactjs

I'm using this module for my twitch API app: https://github.com/joshwcomeau/react-flip-move/
and currently having an issue with the leave animation. The enter animation works perfectly, fine, but unforunately, when I click 'x' on one of the channels, the element (in my case a ) moves up and to the right. How do I make it fade out in its current position?
import React, { Component } from 'react';
import { connect } from 'react-redux';
import FlipMove from 'react-flip-move';
import { selectUser, fetchUser, removeUser } from '../actions/index';
class UsersList extends Component {
constructor(props) {
super(props);
this.state = {
show: 'all',
};
this.fetchInitialUsers(this.props.initialUsers);
}
fetchInitialUsers(users) {
users.map(this.props.fetchUser);
}
renderUser(user) {
const { channelData, streamData } = user;
return (
<tr
key={channelData.display_name}
onClick={() => this.props.selectUser(user)}
className='list-item'>
<td>
<img src={channelData.logo} className='user-logo' />
</td>
<td>
{channelData.display_name}
</td>
<td>
{streamData.stream ?
<span className='online'>Online</span> :
<span className='offline'>Offline</span>}
</td>
<span
className="glyphicon glyphicon-remove"
onClick={() => this.props.removeUser(user)}></span>
</tr>
)
}
showOnline() {
this.setState({
show: 'online'
});
}
showOffline() {
this.setState({
show: 'offline'
});
}
showAll() {
this.setState({
show: 'all'
});
}
render() {
return (
<div className='col-sm-4'>
<div className='text-center'>
<div className='btn-group btn-group-sm' role='group'>
<button
className='btn btn-default'
onClick={this.showAll.bind(this)}>
All
</button>
<button
className='btn btn-default'
onClick={this.showOnline.bind(this)}>
Online
</button>
<button
className='btn btn-default'
onClick={this.showOffline.bind(this)}>
Offline
</button>
</div>
</div>
<div className='container'>
<table className='table table-hover'>
<thead>
<tr>
<th>Logo</th>
<th>Channel</th>
<th>Status</th>
</tr>
</thead>
{/* <tbody> */}
<FlipMove
typeName='tbody' enterAnimation='fade'
leaveAnimation='fade'>
{this.props.users.filter(user => {
const { show } = this.state;
const { streamData } = user;
if (show == 'online') {
return streamData.stream;
}
else if (show == 'offline') {
return !streamData.stream;
}
else {
return user;
}
}).map(this.renderUser.bind(this))}
</FlipMove>
{/* </tbody> */}
</table>
</div>
</div>
)
}
}
function mapStateToProps({ users, initialUsers }) {
return { users, initialUsers };
}
export default connect(mapStateToProps, { selectUser, fetchUser, removeUser })(UsersList);

just add maintainContainerHeight="true" to the flipmove attributes

Related

Update functionality in React - Fetch values and populate onto input boxes

I am a newbie to react and I am trying to fetch data and to populate those values onto the input boxes but I couldn't. I don't understand the error.
My code and screenshot is below.
UpdateLevel.js
import React, { Component } from "react";
import Sidebar from '../Sidebar';
import JobService from "../../Services/JobService";
// import '../css/Create.css';
import './../Job/Job.css';
// import '../../Job.css';
import 'react-toastify/dist/ReactToastify.css';
import { Link } from "react-router-dom";
class UpdateLevel extends React.Component{
constructor(props){
super(props)
this.state={
id:0,
level:'',
levelDes:'',
errors:{}
}
this.id=this.id.bind(this);
this.level=this.level.bind(this);
this.levelDes=this.levelDes.bind(this);
this.UpdateInterviewLevel=this.UpdateInterviewLevel.bind(this);
this.cancel=this.cancel.bind(this);
}
componentDidMount(){
console.log(this.props.match);
JobService.GetInterviewLevelById(localStorage.getItem('id')).then((res)=>{
let level=res.data;
this.setState({
id:localStorage.getItem('id')
,level: level.level,
levelDes:level.levelDes
});
});
}
UpdateInterviewLevel=(e)=>{
e.preventDefault();
let errors={};
// var pattern=new RegExp( /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,16}$/);
// var patt=new RegExp(/\d$/);
let formvalidstatus=true;
if(this.state.level==""){
formvalidstatus=false;
errors["level"]="Please enter Level !";
}
if((this.state.levelDes)==""){
formvalidstatus=false;
errors["levelDes"]="Please enter Description!";
}
this.setState({
errors:errors
});
if(formvalidstatus==true){
let lev={id:parseInt(this.state.id),
level:this.state.level,
levelDes:this.state.levelDes,
};
console.log('lev=>'+lev.level+ " " + lev.levelDes
);
console.log('lev=>'+JSON.stringify(lev));
JobService.UpdateInterviewLevel(lev.id,lev).then(res=>{
window.location="/viewlevel";
localStorage.setItem('Updatestatus',true);
alert('Interview Level Updated successfully')
});
}
}
id(event){
this.setState({id:event.target.value});
}
level(event){
this.setState({level:event.target.value});
}
levelDes(event){
this.setState({levelDes:event.target.value});
}
cancel(){
alert( window.location.replace('http://localhost:3000/'))
}
render(){
// console.log(this.props.match.params);
return(
<div>
<div class="side">
<Sidebar />
</div>
<form className="addformjob">
<h2><strong>Update Interview Level</strong></h2>
<label>Id</label>
<input id="id" name="id" value={ this.state.id} onChange={this.id}></input><br></br>
{/*
<div className="errorMsgJob">{this.state.errors.id}</div>
*/}
<label>Level</label>
<input id="level" type="text" name="level" value={ this.state.level} onChange={this.level}></input><br></br>
<div className="errorMsgJob">{this.state.errors.level}</div>
<br></br>
<label >Description</label>
<input id="levelDes" type="text" name="levelDes" value={ this.state.levelDes} onChange={this.levelDes}></input><br></br>
<div className="errorMsgJob">{this.state.errors.levelDes}</div>
<br></br>
<br></br>
<button id="jobb" className="btn btn-success" onClick={(e)=>this.UpdateInterviewLevel(e)}>Update</button>
<br></br>
<br></br>
<Link to={'/viewlevel'}>
<button className="btn btn-outline-dark" type="submit" onClick={()=>{window.location='/viewlevel'}}>Back</button>
</Link>
<br></br>
</form>
</div>
)
}
}
export default UpdateLevel
JobService.js
import axios from "axios";
const Job_Baseurl="https://localhost:44348/api/Jobs";
class JobService{
GetAllJobs(){
return axios.get(Job_Baseurl+"/GetAllJobs");
}
Addjob(job){
return axios.post(Job_Baseurl+"/AddJob",job);
}
GetJobById(id){
return axios.get(Job_Baseurl+"/GetJobById?id="+id);
}
UpdateJob(id, job){
return axios.put(Job_Baseurl+"/UpdateJob?id="+id,job);
}
DeleteJob(id)
{
return axios.delete(Job_Baseurl+"/DeleteJob?id="+id);
}
AddInterview(job){
return axios.post(Job_Baseurl+"/AddInterviewLevel",job);
}
GetInterviewLevelById(id){
return axios.get(Job_Baseurl+"/GetInterviewLevelById?id="+id);
}
UpdateInterviewLevel(id,level){
return axios.put(Job_Baseurl+"/UpdateInterviewLevel?id="+id,level);
}
GetAllInterviewLevels(){
return axios.get(Job_Baseurl+"/GetAllInterviewLevels");
}
DeleteInterviewLevel(id)
{
return axios.delete(Job_Baseurl+"/DeleteInterviewLevel?id="+id);
}
}
export default new JobService()
ViewLevel.js
import React, { Component } from "react";
import Sidebar from '../Sidebar';
import JobService from "../../Services/JobService";
import '../css/View.css';
import {toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { Link } from "react-router-dom";
import { confirmAlert } from 'react-confirm-alert'; // Import
import 'react-confirm-alert/src/react-confirm-alert.css'; // Import css
class ViewLevel extends React.Component{
constructor(props){
super(props)
this.state={
levels:[],
currentPage:1,
jobsPerPage:5
}
this.addLevel=this.addLevel.bind(this);
this.editLevel=this.editLevel.bind(this);
this.deleteLevel=this.deleteLevel.bind(this);
this.deleteButton=this.deleteButton.bind(this);
this.searchItems=this.searchItems.bind(this);
}
deleteButton(id)
{
confirmAlert({
title:'Delete Confirmation',
message:'Are you sure you want to delete this ?',
buttons:[
{
label:'Delete',
className:'but1',
onClick:()=> this.deleteLevel(id)
},
{
label:'Cancel',
onClick:()=>window.location='/viewlevel'
}
]
});
}
deleteLevel(id){
JobService.DeleteInterviewLevel(id).then(res=>{
this.setState({levels:this.state.levels.filter(level=>level.id!==id)});
});
window.location='/viewlevel';
localStorage.setItem('Deletestatus',true);
}
editLevel(id){
localStorage.setItem('userid',id);
window.location=`/updatelevel/${id}`;
}
addLevel(){
window.location="/interview";
}
displayToast=()=>{
if(localStorage.getItem('Deletestatus')) {
toast('Deleted Successfully',{
position:toast.POSITION.BOTTOM_CENTER,
type:toast.TYPE.SUCCESS,
toastId:'del'
})
}
if(localStorage.getItem('Resgisterstatus')) {
toast('Added Successfully',{
position:toast.POSITION.BOTTOM_CENTER,
type:toast.TYPE.SUCCESS,
toastId:'add',
})
}
if(localStorage.getItem('Updatestatus')) {
toast('Updated Successfully ',{
position:toast.POSITION.BOTTOM_CENTER,
type:toast.TYPE.SUCCESS,
toastId:'update',
})
}
}
clearData=()=>{
localStorage.removeItem('Resgisterstatus');
localStorage.removeItem('Deletestatus');
localStorage.removeItem('Updatestatus');
}
componentDidMount(){
JobService.GetAllInterviewLevels().then((res)=>{
this.setState({levels:res.data});
this.displayToast();
this.clearData();
});
}
searchItems=(event)=>{
let searchval=event.target.value.toLowerCase();
let res=this.state.levels.filter(level=>{
return(((level.id.toString()).indexOf(searchval)!==-1)||
((level.level.toLowerCase()).indexOf(searchval)!==-1)||
((level.levelDes.toLowerCase()).indexOf(searchval)!==-1))
})
if(res==""||searchval==""){
if(res==""){
toast("Searched value not found",
{
position:toast.POSITION.BOTTOM_CENTER,
type: toast.TYPE.WARNING,
toastId:'search',
autoClose:1000,
onClose:function(){
window.location.reload();
}
})
}
else{
window.location.reload();
}
}
else{
this.setState({
levels:res
})
}
}
render(){
const indexOfLastEmpolyee=this.state.currentPage * this.state.jobsPerPage;
const indexOfFirstEmployee=indexOfLastEmpolyee-this.state.jobsPerPage;
const currentEmployees=this.state.levels.slice(indexOfFirstEmployee,indexOfLastEmpolyee);
const pageNumbers=[];
for(let i=1;i<=Math.ceil(this.state.levels.length/this.state.jobsPerPage);i++){
pageNumbers.push(i);
}
const setPage=(pageNum)=>{
this.setState({currentPage:pageNum})
}
return(
<div className="container">
<div class="side">
<Sidebar />
</div>
<div className="addbtn">
{/* <button className="add" onClick={this.addJob}>Add Job</button> */}
<button className="btn btn-outline-success" type="submit" onClick={()=>{window.location='/interview'}}>Add Interview Level</button>
</div>
{/*
<div className="searchbtn">
<input type="text" placeholder="Search here" onChange={(e)=>this.searchItems(e)}/>
</div>
*/}
.
<br></br>
<br></br>
<br></br>
<h3>Interview Level Details</h3>
<br></br>
<table className="table">
<thead className="dark">
<tr>
<th>Level</th>
<th>Description</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{
currentEmployees.map(items=>(
<tr key={items.id}>
<td>{items.level}</td>
<td>{items.levelDes}</td>
<td><button className="btn btn-primary" onClick={()=>this.editLevel(items.id)}>Edit</button></td>
<td><button className="btn btn-danger" onClick={()=>this.deleteButton(items.id)}>Delete</button></td>
</tr>
))}
</tbody>
</table>
<div className="pagination">
{
pageNumbers.map((pageNum,index)=>(
<span key={index} onClick={()=>{setPage(pageNum)}}>
{pageNum}
</span>
))
}
</div>
</div>
)
}
}
export default ViewLevel
When I am clicking the edit button in ViewLevel.js the values doesn't get populated onto the input boxes and I am getting an error like this in console:
GET https://localhost:44348/api/Jobs/GetInterviewLevelById?id=null 404
Uncaught (in promise) AxiosError {message: 'Request failed with status code 404', name:
'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
code: "ERR_BAD_REQUEST"
Thanks in advance.

How can I pass a boolean parameter to another component?

What I'm trying to pass true/false in another component. The user has the possibility to add languages(max2). When the user adds 2 same languages, the validation error will be shown, which to do that I have used some() method which returns true or false.
I tried it with ```localStorge``, but it didn't work.
import React from "react";
export default class AddLanguage extends React.Component {
constructor(props) {
super(props);
this.state = {
message: "",
items: [],
hasError: ""
};
}
updateMessage(event) {
this.setState({
message: event.target.value
});
}
handleClick() {
var items = this.state.items;
items.push(this.state.message);
this.setState({
items: items,
message: ""
});
}
handleItemChanged(i, event) {
const items = event.target.value;
console.log("items", items);
this.setState((prev) => {
const currList = prev.items;
console.log("currList", currList);
const isDuplicate = currList.some(
(lang, idx) => idx !== i && lang) === items
);
if (isDupliacte) {
return { ...prev, hasError: "A BIG ERROR" };
} else {
currList[i] = items;
return { ...prev, items: currList };
}
});
}
handleItemDeleted(i) {
var items = this.state.items;
items.splice(i, 1);
this.setState({
items: items
});
}
renderRows() {
var context = this;
return this.state.items.map(function (o, i) {
return (
<tr key={"item-" + i}>
<td>
<div>
<input
type="text"
value={o}
autoComplete="off"
onChange={context.handleItemChanged.bind(context, i)}
/>
</div>
{this.state.hasError && (
<div>
<label></label>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
className="inline-block mr-2 h-5 w-5"
viewBox="0 0 20 20"
fill="currentColor"
>
</svg>{" "}
{this.state.hasError}
{""}
</div>
</div>
)}
</td>
<td >
<button
type="button"
onClick={context.handleItemDeleted.bind(context, i)}
>
Delete
</button>
</td>
</tr>
);
}, this);
}
render() {
return (
<div>
<div>
<table>
<thead">
<tr>
<th
>
Button
</th>
<th
>
Info
</th>
<th
>
ACTION
</th>
</tr>
</thead>
<tbody>
{this.renderRows()}
</tbody>
</table>
</div>
<div>
<button
className="btn-main"
disabled={this.state.items.length >= 2}
onClick={this.handleClick.bind(this)}
>
<PlusSmIcon />
Add
</button>
</div>
</div>
);
}
}
What I want to pass to the other component is isDuplicate (which might be true/false to another component.

How to map JSON data as a table in React

I'm trying to display data after fetching it, but that does not work :
import React, { Component } from "react";
import { Table, Button, ButtonToolbar } from "react-bootstrap";
const URL = "http://localhost:51644/api/";
let passedAthleteId = 0;
let passedAthleteSessionId = 0;
class AthleteTrainingSession extends Component {
constructor(props) {
super(props);
this.state = {
athleteTrainingSession: [],
discussions: [],
warmups: [],
workouts: [],
stretchings: [],
};
}
componentDidMount() {
this.fetchAthleteTrainingSession();
}
componentDidUpdate() {
this.fetchAthleteTrainingSession();
}
fetchAthleteTrainingSession = () => {
fetch(URL + `Coaches/4/Athletes/1/AthleteSessions/4`)
.then((response) => response.json())
.then((data) => {
this.setState({
athleteTrainingSession: data,
});
});
};
render() {
const {
athleteTrainingSession,
discussions,
warmups,
workouts,
stretchings,
} = this.state;
passedAthleteId = this.props.match.params.athleteId;
passedAthleteSessionId = this.props.match.params.athleteSessionId;
this.discussions = this.state.athleteTrainingSession.Discussions;
this.warmups = this.state.athleteTrainingSession.Warmups;
this.workouts = this.state.athleteTrainingSession.Workouts;
this.stretchings = this.state.athleteTrainingSession.Stretchings;
console.log(athleteTrainingSession);
console.log(this.warmups);
return (
<React.Fragment>
<div>
<h2 className="mt-2">
Programme d'entraînement :{" "}
{athleteTrainingSession.TrainingProgramName}
</h2>
<h4>
Séance d'entraînement : {athleteTrainingSession.TrainingSessionName}
</h4>
</div>
<div>
<ButtonToolbar>
<Button variant="primary">Ajouter</Button>
<Button variant="secondary">Discussion</Button>
</ButtonToolbar>
<h4>Échauffement</h4>
<Table className="mt-4" striped bordered hover size="sm">
<thead>
<tr className="d-flex">
<th className="col-6">Exercice</th>
<th className="col-6">Options</th>
</tr>
</thead>
<tbody>
{warmups.map((warm) => (
<tr className="d-flex" key={warm}>
<td className="col-6">{warm.ExerciseName}</td>
<td className="col-6">
<ButtonToolbar>
<Button className="mr-2" variant="info">
Modifier
</Button>
<Button className="mr-2" variant="danger">
Supprimer
</Button>
</ButtonToolbar>
</td>
</tr>
))}
</tbody>
</Table>
</div>
</React.Fragment>
);
}
}
export default AthleteTrainingSession;
athleteTrainingSession contains the fetched data, and warmups is a sub-object for athleteTrainingSession.
When I console.log(warmups), I can see that it does contain data, but I cannot display it in the table.
athleteTrainingSession contains the fetched data, and warmups is a sub-object for athleteTrainingSession.
When I console.log(warmups), I can see that it does contain data, but I cannot display it in the table.
I think you have misconception of using state in component.
You're able to console the warmups because in your code you console.log(this.warmups), but you render the map with this.state.warmups
you should setState all of the data that you get from fetch, i.e:
fetchAthleteTrainingSession = () => {
fetch(URL + `Coaches/4/Athletes/1/AthleteSessions/4`)
.then((response) => response.json())
.then((data) => {
this.setState({
athleteTrainingSession: data,
warmups: data.Warmups,
workouts: data.Workouts,
discussions: data.Discussions,
stretchings: data.Stretchings,
});
});
};
by doing this way, now you can access the warmups data from this.state.warmups then render it
render() {
const {
athleteTrainingSession,
discussions,
warmups,
workouts,
stretchings,
} = this.state;
return (
<React.Fragment>
...
{warmups.map((warm) => (
<tr className="d-flex" key={warm}>
<td className="col-6">{warm.ExerciseName}</td>
<td className="col-6">
<ButtonToolbar>
<Button className="mr-2" variant="info">
Modifier
</Button>
<Button className="mr-2" variant="danger">
Supprimer
</Button>
</ButtonToolbar>
</td>
</tr>
))}
...
</React.Fragment>
)
}

how to implement react js pagination

i am using react-js-pagination.
i am able to fetch the data and can show the list of data. but i am trying to impelment paggination using react-js-pagination. i am able to show paggination bar in button but not able to get functionality.
here i am trying show 3 records per page.
UI
<div style={pannelFooter}>
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={3}
totalItemsCount={this.state.projectList.length}
pageRangeDisplayed={5}
onChange={this.handlePageChange}
/>
</div>
Method
handlePageChange(pageNumber) {
this.setState({ activePage: pageNumber });
}
Constructor
constructor(props) {
super(props);
this.state = {
activePage: 1,
projectList: [],
originalProjectList: []
};
this.handlePageChange = this.handlePageChange.bind(this);
}
FUll Component
import React, { Component } from 'react';
import ReactDOM from "react-dom";
import Pagination from "react-js-pagination";
import {
BrowserRouter as Router,
Route,
IndexRoute,
Link,
} from 'react-router-dom';
import ProjectDetails from './ProjectDetails';
import DashboardContainer from '../UIcomponent/DashboardContainer';
const pannelWidth = {
width: '90%'
};
const pannelHeader = {
color: 'white'
};
const pannelFooter = {
float: 'right'
};
class ProjectList extends Component {
constructor(props) {
super(props);
this.state = {
activePage: 1,
searchText: '',
isdiagram:true,
isMax:false,
projectList: [],
originalProjectList: []
};
//this.handlePageChange = this.handlePageChange.bind(this);
this.projectDetails = this.projectDetails.bind(this);
this.deleteMessage = this.deleteMessage.bind(this);
this.updateInputValue = this.updateInputValue.bind(this);
this.setSize=this.setSize.bind(this);
}
componentDidMount() {
let d = '';
$.get("http://localhost:8008/api/navigation/all", function (data) {
d = data;
this.setState({
projectList: d,
originalProjectList: d
});
}.bind(this));
}
handlePageChange(pageNumber) {
this.setState({ activePage: pageNumber });
console.log(this.state.projectList);
}
projectDetails(item, index) {
console.log(index);
}
deleteMessage(item, index) {
showconfrim("Do you want to delete this Project?", this.deleteProject(item, index));
console.log('delete');
}
deleteProject(item, index) {
$("#confirmwindow").modal('hide');
console.log('delete');
}
setSize(){
this.setState({
isMax:!this.state.isMax
});
if(!this.state.isMax){
//clear style for jquery animate;
$(this.refs.selfdiv).attr("style",null);
setTimeout(()=>{
$(this.refs.selfdiv).animate({
top:'0px',
right: '0px',
bottom: '0px',
left: '0px'
},500);
},100);
}
console.log(this.props.children);
if(this.props.children[1].props['data-event']){
var self=this;
setTimeout(()=>{
self.props.children[1].props['data-event'].call();
},700);
}
}
updateInputValue(event) {
this.setState({
searchText: event.target.value
}, function () {
let textToSearch = this.state.searchText;
let originalData = this.state.projectList;
if (textToSearch != undefined || textToSearch != '') {
let searchData = [];
for (var i = 0; i < this.state.projectList.length; i++) {
if (this.state.projectList[i].name.indexOf(textToSearch) != -1 || this.state.projectList[i].description.indexOf(textToSearch) != -1) {
searchData.push(this.state.projectList[i]);
}
}
this.setState({
projectList: searchData
});
}
if(textToSearch == '') {
this.setState({
projectList: this.state.originalProjectList,
});
}
});
}
render() {
var listItems = this.state.projectList.map((item, index) => {
return <tr key={index}>
<td onClick={e => this.projectDetails(item, index)}><a><u>{item.name}</u></a></td>
<td>{item.description}</td>
<td><i className="glyphicon glyphicon-trash" onClick={e => this.deleteMessage(item, index)}></i></td>
</tr>
});
return (
<div className="container" style={pannelWidth} ref="selfdiv">
<br />
<div className="panel panel-primary">
<div className="panel-heading">
<div className="row">
<div className="col-md-2 col-lg-2">
<h4 style={pannelHeader}>Project List</h4>
</div>
<div className="col-md-6 col-lg-6">
<input type="text" className="form-control" placeholder="Search" value={this.state.searchText} onChange={this.updateInputValue}/>
</div>
<div className="col-md-2 col-lg-2">
<button className="btn btn-sm btn-success">Create New Project</button>
</div>
<div className="col-md-2 col-lg-2">
<div className="captiontoolbar buttoncontainer">
<span onClick={this.setSize} style={pannelFooter} className={
this.state.isMax ? ("boxMaxsize glyphicon glyphicon-resize-small") : ("boxMaxsize glyphicon glyphicon-fullscreen")
}></span>
</div>
</div>
</div>
</div>
<div className="panel-body">
<table className="table table-striped">
<thead>
<tr>
<th><b>Project Name</b></th>
<th><b>Description</b></th>
<th><b>Action</b></th>
</tr>
</thead>
<tbody>
{listItems}
</tbody>
</table>
</div>
<div style={pannelFooter}>
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={3}
totalItemsCount={this.state.projectList.length}
pageRangeDisplayed={5}
onChange={this.handlePageChange.bind(this)}
/>
</div>
</div>
</div>
);
}
}
export default ProjectList;
var indexOfLastTodo = this.state.activePage * this.state.itemPerPage;
var indexOfFirstTodo = indexOfLastTodo - this.state.itemPerPage;
var renderedProjects = this.state.projectList.slice(indexOfFirstTodo, indexOfLastTodo);
var listItems = renderedProjects.map((item, index) => {
return <tr key={index}>
<td onClick={e => this.projectDetails(item, index, e)}><a><u>{item.projectName}</u></a></td>
<td>{item.description}</td>
<td><i className="glyphicon glyphicon-trash" onClick={(e) => { if (window.confirm('All its related data will be deleted. Are you sure you want to delete?')) this.deleteMessage(item, index) } } > </i></td>
<td><i className="glyphicon glyphicon-edit" id="edit" onClick={e => this.editProject(item, index, e)}></i></td>
</tr>
});
Here need to update the projectList array using slice(firstIndex, lastIndex). then subarray should be use for rander purpose.
and paggination tag should be like below
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={this.state.itemPerPage}
totalItemsCount={this.state.originalProjectList.length}
pageRangeDisplayed={5}
onChange={this.handlePageChange.bind(this)}
/>
Take advantage of ES6.
So, insted of doing something like this:
this.handlePageChange = this.handlePageChange.bind(this);
You can do this:
handlePageChange = (pageNumber) => {
console.log(`active page is ${pageNumber}`);
this.setState({activePage: pageNumber});
}
Hope this helps.

React JS assign separate onclick event to every row of table

I have a table which have a setting icon as the last column and whenever a user clicks on it, it should pop open a setting menu. To toggle between active class I used state and passed it to the array.map function, but what is happening is whenever a user clicks on one setting icon all the menus open simultaneously and the reason is they all have same click event and same state variable. How can I change it to where only the clicked setting icon should have its menu opened? My code is given below.
import React, { Component, PropTypes } from 'react';
import '../../../assets/custom_css/tables/unstackable_very_basic_striped_users_table.css';
import { v4 } from 'node-uuid';
import Language from '../../../assets/language';
class UnstackableVeryBasicStripedUsersTable extends Component {
static propTypes = {
rows: PropTypes.array.isRequired
};
constructor(props) {
super(props);
this.getTableRows = this.getTableRows.bind(this);
this.open_setting_menu = this.open_setting_menu.bind(this);
this.state = {
is_action_menu_active: false
};
}
getTableRows() {
const { rows } = this.props;
return rows.map(row => {
let drop_down_class = (this.state.is_action_menu_active) ? "active" : "";
let menu_class = (this.state.is_action_menu_active) ? "transition visible" : "";
return <tr key={v4()}>
{row.map(info => {
return <td key={v4()}>
{info}
</td>
})}
<td>
<div className={"ui right pointing dropdown icon " + drop_down_class} onClick={this.open_setting_menu}>
<i className="setting icon"/>
<div className={"menu " + menu_class}>
<div className="item">Edit</div>
<div className="item">Delete</div>
</div>
</div>
</td>
</tr>
});
}
open_setting_menu() {
this.setState({
is_action_menu_active: !this.state.is_action_menu_active
});
}
render() {
return <table className="ui unstackable celled very basic striped table unstackable_very_basic_striped_table">
<thead>
<tr>
<th>{Language.name}</th>
<th>{Language.role}</th>
<th>{Language.department}</th>
<th>{Language.action}</th>
</tr>
</thead>
<tbody>
{this.getTableRows()}
</tbody>
</table>
}
}
export default UnstackableVeryBasicStripedUsersTable;
If you want to use a single component, you can save the index of the selected row in the state:
import React, { Component, PropTypes } from 'react';
import '../../../assets/custom_css/tables/unstackable_very_basic_striped_users_table.css';
import { v4 } from 'node-uuid';
import Language from '../../../assets/language';
class UnstackableVeryBasicStripedUsersTable extends Component {
static propTypes = {
rows: PropTypes.array.isRequired
};
constructor(props) {
super(props);
this.getTableRows = this.getTableRows.bind(this);
this.open_setting_menu = this.open_setting_menu.bind(this);
this.state = {
selected_row_index: 0,
is_action_menu_active: false
};
}
getTableRows() {
const { rows } = this.props;
return rows.map((row, index) => {
let drop_down_class = (this.state.is_action_menu_active && this.state.selected_row_index === index) ? "active" : "";
let menu_class = (this.state.is_action_menu_active && this.state.selected_row_index === index) ? "transition visible" : "";
return <tr key={v4()}>
{row.map(info => {
return <td key={v4()}>
{info}
</td>
})}
<td>
<div className={"ui right pointing dropdown icon " + drop_down_class} onClick={() => this.open_setting_menu(index)}>
<i className="setting icon"/>
<div className={"menu " + menu_class}>
<div className="item">Edit</div>
<div className="item">Delete</div>
</div>
</div>
</td>
</tr>
});
}
open_setting_menu(index) {
this.setState({
is_action_menu_active: !this.state.is_action_menu_active,
selected_row_index: index
});
}
render() {
return <table className="ui unstackable celled very basic striped table unstackable_very_basic_striped_table">
<thead>
<tr>
<th>{Language.name}</th>
<th>{Language.role}</th>
<th>{Language.department}</th>
<th>{Language.action}</th>
</tr>
</thead>
<tbody>
{this.getTableRows()}
</tbody>
</table>
}
}
export default UnstackableVeryBasicStripedUsersTable;

Resources