TypeError: h is undefined - reactjs

I have the following code working properly except when I click on the following button inside projectSpacedGrid function, I get errors in the browser's console as shown below the code:
<Button
label="Associate Project Spaces"
icon="pi pi-plus"
style={{ marginRight: ".25em", marginTop: ".25em" }}
onClick={e =>
this.setState({
assocAssetsVisible: true
})
}
/>
Here's my full code( I've removed lot of code to keep it as small as possible):
import React from "react";
import * as ReactDOM from "react-dom";
import JqxTabs from "jqwidgets-scripts/jqwidgets-react-tsx/jqxtabs";
import JqxGrid, {
IGridProps,
jqx
} from "jqwidgets-scripts/jqwidgets-react-tsx/jqxgrid";
import JqxButton from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons';
import JqxInput from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxinput';
import JqxDateTimeInput from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxdatetimeinput';
import JqxWindow from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow';
import JqxDropDownList, { IDropDownListProps } from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxdropdownlist';
import JqxNotification from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxnotification';
import { Button } from "primereact/button";
import { Growl } from "primereact/growl";
import { properties } from ".././properties";
import { Messages } from "primereact/messages";
import axios from "axios/index";
type Props = {
project,
username
};
export interface AssetsState extends IGridProps {
//export interface AssetsState extends IDropDownListProps {
visible: boolean,
assocAssetsVisible: boolean,
project: {},
selectedAsset: [],
addEditLabel: {},
selectedRowIndex: number,
deleteDialogVisible: boolean,
dropdownlistSource:IDropDownListProps["source"];
rendertoolbar: (toolbar: any) => void;
}
export class Assets extends React.PureComponent<Props, AssetsState> {
private growl = React.createRef<Growl>();
//Created Refs for a particular div
private projectSpacesGridElement = React.createRef<HTMLDivElement>();
//Created Refs for the desired widgets (JQXGrid and JQXTabs)
private assetsDataGrid = React.createRef<JqxGrid>();
private myTabs = React.createRef<JqxTabs>();
//Created Refs for editing popups for project spaces tab
private assetsEditWindow = React.createRef<JqxWindow>();
private assetsAddWindow = React.createRef<JqxWindow>();
private id = React.createRef<JqxInput>();
private assetsTypeId = React.createRef<JqxInput>();
private assetCategoryId = React.createRef<JqxInput>();
private locationTypeId = React.createRef<JqxInput>();
private statusIndicatorId = React.createRef<JqxInput>();
private uri = React.createRef<JqxInput>();
private fileName = React.createRef<JqxInput>();
private fileAddCDSName = React.createRef<JqxInput>();
private fileVersion = React.createRef<JqxInput>();
private fileEncodingId = React.createRef<JqxInput>();
private ownerId = React.createRef<JqxInput>();
private createdDate = React.createRef<JqxDateTimeInput>();
private updatedDate = React.createRef<JqxDateTimeInput>();
private createdBy = React.createRef<JqxInput>();
private assetDescription = React.createRef<JqxInput>();
private assetCDSDescription = React.createRef<JqxInput>();
private msgNotification = React.createRef<JqxNotification>();
private firstTabButtonContent = "Add New Project Space ";
private editrow: number = -1;
private baseUrl = properties.baseUrlWs;
private messages = React.createRef<Messages>();
constructor(props: Props) {
super(props);
this.saveEditCDSBtn = this.saveEditCDSBtn.bind(this);
this.cancelEditCDSBtn = this.cancelEditCDSBtn.bind(this);
this.savenewCDSpaceBtn = this.savenewCDSpaceBtn.bind(this);
this.cancelnewCDSpaceBtn = this.cancelnewCDSpaceBtn.bind(this);
const rendertoolbar = (toolbar: any): void => {
const addPSRowClick = () => {
this.assetsAddWindow.current!.open();
};
ReactDOM.render(
<div style={{ margin: '5px' }}>
<div id="button1" style={{ float: 'left' }}>
<JqxButton theme={'material'} onClick={addPSRowClick} width={155} value={'Add Project Space'} />
</div>
</div>,
toolbar[0]
);
};
this.state = {
visible: false,
project: {},
assocAssetsVisible: false,
selectedAsset: [],
addEditLabel: {},
selectedRowIndex: null,
deleteDialogVisible: false,
rendergridrows: (params: any): any[] => {
const data = params.data;
return data;
},
rendertoolbar,
dropdownlistSource:[
{value:0, label:'Individual'},
{value:1, label:'Project'},
{value:2, label:'Institution'},
{value:3, label:'Public'}
]
};
}
public render() {
console.log(this.state.selectedAsset);
return (
<div>
<JqxTabs
ref={this.myTabs}
theme={"arctic"}
width="1390px"
//height={560}
//height={100}
initTabContent={this.initWidgets}
onSelected={this.onTabSelected}
>
<ul>
<li style={{ marginLeft: 30 }}>
<div style={{ height: 20, marginTop: 5 }}>
<div style={{ float: "left" }}></div>
<div
style={{
marginLeft: 4,
verticalAlign: "middle",
textAlign: "center",
float: "left"
}}
>
Project Spaces
</div>
</div>
</li>
</ul>
<div style={{ overflow: "hidden" }}>
<div id="jqxGrid" ref={this.projectSpacesGridElement} />
<div style={{ marginTop: 10, height: "15%", width: "100%" }}></div>
</div>
</JqxTabs>
<JqxWindow ref={this.assetsEditWindow} width={250} height={230} resizable={false}
isModal={false} autoOpen={false} modalOpacity={'0.01'} position={{ x: 68, y: 368 }}>
<div>Edit</div>
<div style={{ overflow: 'hidden' }}>
<table>
<tbody>
<tr>
<td align={'right'}>Name :</td>
<td align={'left'}>
<JqxInput ref={this.fileName} width={150} height={23} />
</td>
</tr>
<tr>
<td align={'right'}>Version:</td>
<td align={'left'}>
<JqxInput ref={this.fileVersion} width={150} height={23} />
</td>
</tr>
<tr>
<td align={'right'}>Description:</td>
<td align={'left'}>
<JqxInput ref={this.assetDescription} width={150} height={23} />
</td>
</tr>
<tr>
<td align={'right'}>Visibility Indicator:</td>
<td align={'left'}>
{/* <JqxInput ref={this.visibilityIndicatorID} width={150} height={23} /> */}
<JqxDropDownList width={100} height={20} source={this.state.dropdownlistSource} selectedIndex={0} autoDropDownHeight={true}/>
</td>
</tr>
<tr hidden>
<td align={'right'}>ID:</td>
<td align={'left'}>
<JqxInput ref={this.id} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Location Type ID:</td>
<td align={'left'}>
<JqxInput ref={this.locationTypeId} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Asset Category ID:</td>
<td align={'left'}>
<JqxInput ref={this.assetCategoryId} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Asset Type ID:</td>
<td align={'left'}>
<JqxInput ref={this.assetsTypeId} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Status Indicator ID:</td>
<td align={'left'}>
<JqxInput ref={this.statusIndicatorId} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>URI:</td>
<td align={'left'}>
<JqxInput ref={this.uri} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>File Encoding ID:</td>
<td align={'left'}>
<JqxInput ref={this.fileEncodingId} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Owner ID:</td>
<td align={'left'}>
<JqxInput ref={this.ownerId} width={150} height={23} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Created Date:</td>
<td align={'left'}>
<JqxDateTimeInput ref={this.createdDate}
width={150} height={23} formatString={'F'} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Updated Date:</td>
<td align={'left'}>
<JqxDateTimeInput ref={this.updatedDate}
width={150} height={23} formatString={'F'} />
</td>
</tr>
<tr hidden>
<td align={'right'}>Created By:</td>
<td align={'left'}>
<JqxInput ref={this.createdBy} width={150} height={23} />
</td>
</tr>
<tr>
<td align={'right'} />
<td style={{ paddingTop: '10px' }} align={'right'}>
<JqxButton style={{ display: 'inline-block', marginRight: '5px' }} onClick={this.saveEditCDSBtn} width={50}>
Save
</JqxButton>
<JqxButton style={{ display: 'inline-block', marginRight: '5px' }} onClick={this.cancelEditCDSBtn} width={50}>
Cancel
</JqxButton>
</td>
</tr>
</tbody>
</table>
</div>
</JqxWindow>
<JqxWindow ref={this.assetsAddWindow} width={250} height={230} resizable={false}
isModal={false} autoOpen={false} modalOpacity={'0.01'} position={{ x: 68, y: 368 }}>
<div>{this.firstTabButtonContent}</div>
<div style={{ overflow: 'hidden' }}>
<table>
<tbody>
<tr>
<td align={'right'}>Name:</td>
<td align={'left'}>
<JqxInput ref={this.fileAddCDSName} width={150} height={23} />
</td>
</tr>
<tr>
<td align={'right'}>Description:</td>
<td align={'left'}>
<JqxInput ref={this.assetCDSDescription} width={150} height={23} />
</td>
</tr>
<tr>
<td align={'right'}>Visibility Indicator:</td>
<td align={'left'}>
<JqxDropDownList width={100} height={20} source={this.state.dropdownlistSource} selectedIndex={0} autoDropDownHeight={true} />
</td>
</tr>
<tr>
<td align={'right'} />
<td style={{ paddingTop: '10px' }} align={'right'}>
<JqxButton style={{ display: 'inline-block', marginRight: '5px' }} onClick={this.savenewCDSpaceBtn} width={50}>
Save
</JqxButton>
<JqxButton style={{ display: 'inline-block', marginRight: '5px' }} onClick={this.cancelnewCDSpaceBtn} width={50}>
Cancel
</JqxButton>
</td>
</tr>
</tbody>
</table>
</div>
</JqxWindow>
<JqxNotification ref={this.msgNotification}
width={250} position={'top-left'} opacity={0.9} autoOpen={false}
autoClose={true} animationOpenDelay={800} autoCloseDelay={3000} template={'info'} appendContainer={'#forNotification'}>
<div>
Record Deleted Successfully!
</div>
</JqxNotification>
</div>
);
}
//Tab 1
private projectSpacesGrid = () => {
const source: any = {
datafields: [
{ name: "id", type: "long" },
{ name: "assetsTypeId", type: "long" },
{ name: "fileName", type: "string" },
{ name: "locationTypeId", type: "long" },
{ name: "uri", type: "string" },
{ name: "fileVersion", type: "string" },
{ name: "fileEncodingId", type: "long" },
{ name: "ownerId", type: "long" },
{ name: "createdDate", type: "date",format: "dd-MMM-yy" },
{ name: "assetCategoryId", type: "long" },
{ name: "assetDescription", type: "string" },
{ name: "createdBy", type: "string" },
{ name: "updatedDate", type: "date",format: "dd-MMM-yy" },
{ name: "statusIndicatorId", type: "long" },
{ name: "visibilityIndicatorId", type: "long" },
{ name: "displayedValues", type: "string" }
],
deleterow: (rowid: number,commit:any): void => {
console.log("Delete row method called in source of Project Spaces");
console.log("Role ID:" + rowid);
commit(true);
},
datatype: "json",
root: "assets",
url: this.baseUrl + `api/assets/search/getAssetsByProjectId`
};
const dataAdapter = new jqx.dataAdapter(source, {
//async: false,
autoBind: true,
downloadComplete: (data: any, status: any, xhr: any): void => {
source.totalrecords = parseInt(data["page"].totalElements);
console.log("Total Assets Records check"+source.totalrecords);
},
formatData: (data: any): any => {
data.value = this.props.project.id;
data.page = data.pagenum;
data.size = data.pagesize;
if (data.sortdatafield && data.sortorder) {
data.sort = data.sortdatafield + "," + data.sortorder;
}
return data;
},
loadError: (xhr: any, status: any, error: any) => {
alert('Error loading "' + source.url + '" : ' + error);
}
});
const columns: IGridProps["columns"] = [
{ datafield: "id", text: "ID Number", width: 100,hidden:true },
{ datafield: "assetsTypeId", text: "Assets Type ID", width: 100, hidden: true },
{ datafield: "fileName", text: "Name", width: 275 },
{ datafield: "fileVersion", text: "File Version", width: 275, hidden: true },
{ datafield: "fileEncodingId", text: "File Encoding", width: 275, hidden: true },
{ datafield: "ownerid", text: "Owner ID", width: 100, hidden: true },
{ datafield: "assetCategoryId", text: "Asset Category ID", width: 100, hidden: true },
{ datafield: "statusIndicatorId", text: "Status Indicator ID", width: 100, hidden: true },
{ datafield: "visibilityIndicatorId", text: "Visibility Indicator ID", width: 100, hidden: true },
{ datafield: "displayedValues", text: "Display Values", width: 100, hidden: true },
{
datafield: "assetDescription",
text: "Description",
width: 250
},
{ datafield: "locationTypeId", text: "Location Type", width: 150 },
{ datafield: "uri", text: "URI", width: 150 },
{ datafield: "ownerId", text: "Owner", width: 150 },
{
//cellsformat: "d",
cellsformat: "MM/dd/yyyy",
datafield: "createdDate",
text: "Created Date",
width: 150
},
{
//cellsformat: "d",
cellsformat: "MM/dd/yyyy",
datafield: "updatedDate",
text: "Updated Date",
width: 100
},
{
text: "Delete ",
buttonclick: (): void => {
},
cellsrenderer: (): string => {
return "Delete";
},
columntype: "button",
datafield: "Delete",
width: 80
},
{
text: "Edit Asset",
buttonclick: (row: number): void => {
// show the popup window.
this.assetsEditWindow.current!.open();
},
cellsrenderer: (): string => {
return "Edit";
},
columntype: "button",
datafield: "Edit",
width: 80
}
];
const grid =
this.state.visible || this.state.assocAssetsVisible ? null : (
<div>
<JqxGrid
ref={this.assetsDataGrid}
width={"100%"}
height={"100%"}
theme={"arctic"}
source={dataAdapter}
columns={columns}
showtoolbar={true}
pageable={true}
pagesize={50}
scrollmode={"default"}
rendertoolbar={this.state.rendertoolbar}
sortable={true}
/>
<Button
label="Associate Project Spaces"
icon="pi pi-plus"
style={{ marginRight: ".25em", marginTop: ".25em" }}
onClick={e =>
this.setState({
assocAssetsVisible: true
})
}
/>
</div>
);
ReactDOM.render(grid, this.projectSpacesGridElement.current!);
};
private saveEditCDSBtn(): void {
if (this.editrow >= 0) {
this.assetsEditWindow.current!.hide();
}
}
private cancelEditCDSBtn(): void {
this.assetsEditWindow.current!.hide();
}
private savenewCDSpaceBtn(): void {
this.assetsAddWindow.current!.hide();
}
private cancelnewCDSpaceBtn(): void {
this.assetsAddWindow.current!.hide();
}
private initWidgets = (tab: any) => {
switch (tab) {
case 0:
this.projectSpacesGrid();
break;
}
};
private onTabSelected = (event: any) => {
if (event.args) {
let tabIndex = event.args.item;
switch (event.args.item) {
case 0:
this.assetsAddWindow.current!.setTitle(this.firstTabButtonContent);
break;
}
}
};
}
Error Below:
The above error occurred in the <JqxWindow> component:
in JqxWindow (created by Assets)
in div (created by Assets)
in Assets (created by ProjectTabView)
in div (created by TabView)
in div (created by TabView)
in div (created by TabView)
in TabView (created by ProjectTabView)
in ProjectTabView (created by ProjectView)
in div (created by ProjectView)
in ProjectView (created by Route)
in Route (created by Main)
in Switch (created by Main)
in div (created by Main)
in div (created by Main)
in Router (created by BrowserRouter)
in BrowserRouter (created by Main)
in Main
in ErrorBoundary
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
TypeError: "h is undefined"
propertyChangedHandler webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxwindow.js?:8
setvalueraiseevent webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:16
set webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:16
each webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:8
set webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:16
jqxWidgetProxy webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:16
b.jqx.jqxWidget/b.fn[h]/< webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:16
each webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:8
each webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:8
h webpack:///./node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js?:16
setOptions webpack:///./node_modules/jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow/react_jqxwindow.esm.js?:88
componentDidUpdate webpack:///./node_modules/jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow/react_jqxwindow.esm.js?:82
React 6
unstable_runWithPriority webpack:///./node_modules/scheduler/cjs/scheduler.development.js?:818
React 5
unstable_runWithPriority webpack:///./node_modules/scheduler/cjs/scheduler.development.js?:818
React 6
Adding screenshots of complete error from the browser console:
Is it something related to associateAssetsVisible:true variable that I'm using?

Related

how to close react dropdown componet after out focus?

I've created a react dropdown component to show a list of data. this data get from server and I handle dropdown list show/hide with display property.
I want to use this component in other components. I need that closed after click out of component in the parent.
export default class Dropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
show: false,
value: "",
data: []
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.getData();
}
async getData() {
const response = await fetch(this.props.url);
const data = await response.json();
this.setState({ data: data });
}
handleChange(event) {
this.setState({ value: event.target.value });
}
render() {
return (
<div className={styles.container}>
<input type="text" name="name"
onClick={() => this.setState({ show: !this.state.show })}
className={styles.bottonStyle}
value={this.state.value}
onChange={this.handleChange}
/>
<div style={Object.assign({
position: "absolute", backgroundColor: "#f9f9f9", minWidth: "350px", zIndex: "1"
}, this.state.show ? { display: "block" } : { display: "none" })} >
<div style={Object.assign({ backgroundColor: "lightgray" }, !this.state.showMounthList ? { display: "block" } : { display: "none" })} >
<table>
<tr style={{ backgroundColor: "orange" }}>
<th>Id</th>
<th>code</th>
<th>name</th>
</tr>
{
this.state.data.length > 0 ? (
this.state.data.map((item) => {
return <tr>
<td>{item.id}</td>
<td>{item.code}</td>
<td>{item.fullName}</td>
</tr>
})
) : null
}
</table>
</div>
</div >
</div >);
}}

How to access data outside the function using axios and react js

when call the retriveStudentPhoto() function from h1 tag . I can't get the value return .How do I solve this.
Thanks in advance .
{data.map((val, index) => (
<tr>
<td style={{ outline: 'none' }} data-heading="Photo">
<h1{ retriveStudentPhoto(val.email) }</h1> /*call
this function */
</td>
))}
function retriveStudentPhoto (email) {
var photo = ""
axios.get(`/user-info/${email}`)
.then((result)=>{
photo = result.data[0].profile_photo;
}).catch((error)=>error)
return photo ;
}
Since the function is inside the map , there will be call multiple times and the value will be returned each time. I used the useState hook but not getting results as per demand.
please help me more. Thanks in advance.
complete Code :
import React, { useEffect, useState } from 'react';
import { Button, Alert } from 'react-bootstrap';
import $ from 'jquery';
import axios from '../../config/axios';
import '../Attendance_Table/css/App.scss';
import { useAuth } from "../../contexts/AuthContext";
import { Link, useHistory } from 'react-router-dom';
function PeopleList({ match }) {
const course_code = match.params.course_code;
const { currentUser } = useAuth();
const history = useHistory();
const [msg, setMsg] = useState("");
const [course_name, setcourse_name] = useState("");
var breakOn = 'medium'
let tableClass = 'table-container__table';
if (breakOn === 'small') {
tableClass += ' table-container__table--break-sm';
} else if (breakOn === 'medium') {
tableClass += ' table-container__table--break-md';
} else if (breakOn === 'large') {
tableClass += ' table-container__table--break-lg';
}
const headingColumns = ['Photo', 'Student ID', 'Name', 'Email']
const headingColumns2 = ['Photo', 'Name', 'Email']
const [data, setData] = useState([]);
const [studentsPhoto, setStudentsPhoto] = useState([]);
const [techInfo, setTechInfo] = useState([]);
useEffect(() => {
axios.get(`/course/info/${course_code}`).then((result) => {
setcourse_name(result.data[0].course_name)
})
SearchHandle();
}, [])
let SearchHandle = () => {
axios.get(`people/${course_code}`).then((result) => {
setData(result.data)
// teacher info retrieve
axios.get(`user-info/${result.data[0].tecEmail}`)
.then((res) => {
setTechInfo(res.data[0]);
})
//close teacher retrieve
let student_photo = [];
let promises = [];
for (let i = 0; i < result.data.length; i++) {
promises.push(
axios.get(`/user-info/${result.data[i].email}`)
.then((res) => {
student_photo.push(res?.data[0]?.profile_photo)
})
)
}
Promise.all(promises).then(() => {
setStudentsPhoto(student_photo);
})
}).catch((err) => console.log(err))
}
function retriveStudentPhoto(email) {
var photo = "";
axios.get(`/user-info/${email}`)
.then((result) => {
var photo = result.data[0].profile_photo;
}).catch((error) => error)
return photo;
}
return (
<div>
{/* {msg ? ( */}
<div>
<div className="table-container" style={{ backgroundColor: 'white' }}>
<div className="table-container__title">
<h5>People -- {course_name}({course_code})</h5>
</div>
<h5 style={{ padding: '10px', fontFamily: 'roboto' }}>Teacher</h5>
<table style={{ outline: 'none', border: 'none' }} className={tableClass}>
<thead>
<tr>
{headingColumns2.map((col, index) => (
<th data-heading={index} key={index}>{col}</th>
))}
</tr>
</thead>
<tbody>
<tr>
<td style={{ outline: 'none' }} data-heading="Photo">
{techInfo.profile_photo ? (
<img style={{ borderRadius: '150px', height: '40px', width: '40px' }}
src={techInfo.profile_photo} />
) : (
<img style={{ borderRadius: '150px', height: '40px', width: '40px' }}
src="https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/s75-c-fbw=1/photo.jpg" />
)}
</td>
<td data-heading="Student Name">{techInfo.name} </td>
<td data-heading="Student Email"><span style={{ fontSize: '11.5px' }}>{techInfo.email}</span> </td>
</tr>
</tbody>
</table><br />
<br />
{data.length ? (
<table style={{ outline: 'none', border: 'none' }} className={tableClass}>
<thead>
<tr>
{headingColumns.map((col, index) => (
<th data-heading={index} key={index}>{col}</th>
))}
</tr>
</thead>
<tbody>
{data.map((val, index) => (
<tr>
<td style={{ outline: 'none' }} data-heading="Photo">
<h1>{retriveStudentPhoto(val.email)}</h1>
</td>
<td style={{ outline: 'none' }} data-heading="Student ID">{val.student_id}</td>
<td data-heading="Student Name">{val.student_name} </td>
<td data-heading="Student Email"><span style={{ fontSize: '11.5px' }}>{val.email}</span> </td>
</tr>
))}
</tbody>
</table>
) : (
<div>
<Alert className="md-4 w-100" variant="danger">
No Student add to this course yet
</Alert>
</div>
)}
<br />
<div style={{ textAlign: 'center', paddingBottom: '5px' }}>
<Link to={`/attendance-sheet/${course_code}`}><span>Back to {course_code}</span></Link>
</div>
</div>
</div>
{/* ) : ""} */}
</div>
);
}
export default PeopleList;
Render is a pure, synchronous function. If you need to make asynchronous calls then do this in a lifecycle, in this case, a useEffect hook and store the results in state to be rendered.
Iterate over the result.data array and issue the GET request, and when the request resolves issue a functional state update to create a new data array, using the iterated element's index to inject a new photo property.
const SearchHandle = () => {
axios.get(`people/${course_code}`)
.then((result) => {
setData(result.data);
result.data.forEach(async (item, index) => {
try {
const result = await axios.get(`/user-info/${item.email}`);
const photo = result.data[0].profile_photo;
setData(data => data.map(
(el, i) => i === index
? { ...el, photo }
: el)
)
} catch(error) {
// log error, etc...
}
});
...
}
In the render access the new photo property you added above.
{data.map((val, index) => (
<tr key={val.student_name}>
<td style={{ outline: 'none' }} data-heading="Photo">
<h1>{val.photo}</h1>
</td>
<td style={{ outline: 'none' }} data-heading="Student ID">{val.student_id}</td>
<td data-heading="Student Name">{val.student_name} </td>
<td data-heading="Student Email">
<span style={{ fontSize: '11.5px' }}>{val.email}</span>
</td>
</tr>
)
)}
You are trying to use a function with async data in the render, so probably you dont have the data yet.
Try to keep the data from that axios.get in the state, youd probably want also to implement useEffect to make the call and store it to the state when component mounts

Can't fix the width of React-Table column

Super noob question here, I'm trying to fix the widths of my react-table columns but it doesn't change (it stays at generated according to the width of the items inside), most of this table is from a tutorial to be honest so I'm not sure how most of it works.
I'm using react hooks, and react-table v7.7!
const data = useMemo(() => expenses, [expenses]);
const columns = useMemo(
() => [
{
Header: "Date",
accessor: "date",
width: 100
},
{
Header: "Expense",
accessor: "expense",
width: 200
},
{
Header: "Amount",
accessor: "amount",
width: 100
},
{
Header: " ",
width: 100,
Cell: ({ row }) => (
<div>
<button onClick={() => editHandler(row.original)}>Edit</button>
<button onClick={() => deleteHandler(row.original)}>Delete</button>
</div>
),
},
],
[]
);
....
<table className="expenses-table" {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th className="table-header" {...column.getHeaderProps()}>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td className="table-data" {...cell.getCellProps()}>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
In order for width props to work, i think you need to add either of the following css/style to your expense-table class or to your <table> tag directly. This is to handle the overflowing behavior, since currently the contents have no choice but to resize the table column.
table.expense-table { table-layout:fixed; }
table.expense-table td { overflow: hidden; }

React-table and go to first/last page

I'm trying to add "go to" first/last page buttons to the React-Table by overwriting PreviousComponent and NextComponent but it looks like both components are connected to the previous/next page functionality behaviours.
Is there any other way to add those two buttons to the default pagination component?
You can customise the text as required. I have mocked the data, you can pass the actual data as required
See the code
App.js
import React from "react";
import styled from "styled-components";
import { useTable, usePagination } from "react-table";
import makeData from "./makeData";
const Styles = styled.div`
padding: 1rem;
table {
border-spacing: 0;
border: 1px solid black;
tr {
:last-child {
td {
border-bottom: 0;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
.pagination {
padding: 0.5rem;
}
`;
function Table({ columns, data }) {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page, // Instead of using 'rows', we'll use page,
// which has only the rows for the active page
// The rest of these things are super handy, too ;)
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state: { pageIndex, pageSize }
} = useTable(
{
columns,
data,
initialState: { pageIndex: 2 }
},
usePagination
);
// 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()}>
{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>
{/*
Pagination can be built however you'd like.
This is just a very basic UI implementation:
*/}
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{"First"}
</button>{" "}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{"<"}
</button>{" "}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{">"}
</button>{" "}
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{"Last"}
</button>{" "}
<span>
Page{" "}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{" "}
</span>
<span>
| 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" }}
/>
</span>{" "}
<select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</>
);
}
function App() {
const columns = React.useMemo(
() => [
{
Header: "Name",
columns: [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Last Name",
accessor: "lastName"
}
]
},
{
Header: "Info",
columns: [
{
Header: "Age",
accessor: "age"
},
{
Header: "Visits",
accessor: "visits"
},
{
Header: "Status",
accessor: "status"
},
{
Header: "Profile Progress",
accessor: "progress"
}
]
}
],
[]
);
const data = React.useMemo(() => makeData(100000), []);
return (
<Styles>
<Table columns={columns} data={data} />
</Styles>
);
}
export default App;
Working codesandbox
For v6 I have ended up overwriting PaginationComponent
<ReactTable
....
PaginationComponent={PaginationComponent}
....
>
with modified default code as custom PaginationComponent where I have added
<div className="-first">
<button
disabled={!canPrevious}
onClick={() => {
if (!canPrevious) return
this.changePage(0)
}}
> First </button>
</div>
and
<div className="-last">
<button
onClick={() => {
if (!canNext) return
this.changePage(pages)
}}
disabled={!canNext}
> Last </button>
</div>

Using CheckboxEditor with react-data-grid

I'm new to React and I'm trying to get the react-data-grid to display a checkbox for one of the columns. I have imported react-data-grid and react-data-grid-addons but I'm not sure how to pass the required props to the CheckboxEditor.
import React, {PropTypes} from "react";
import {connect} from "react-redux";
import {bindActionCreators} from "redux";
import * as identityActions from "../../actions/identityActions";
import * as defectViewActions from "../../actions/defectViewActions";
import MultiSelectBox from "../common/MultiSelectBox";
import ReactDataGrid from "react-data-grid";
import Editors from "react-data-grid-addons";
const {CheckboxEditor} = Editors;
class UserProfilePage extends React.Component {
constructor(props, context) {
super(props, context);
this.setReportingArea = this.setReportingArea.bind(this);
this.rowGetter = this.rowGetter.bind(this);
this.onCellChanged = this.onCellChanged.bind(this);
this.state = {
viewColumns: [],
summaryColumns: [],
detailColumns: [],
commentColumns: [],
columns: [
{
key: "Name",
name: "Column",
resizable: false,
width: 200,
editable: false
},
{
key: "SummaryView",
name: "Summary",
resizable: false,
width: 80,
editor: <CheckboxEditor value={this.props.value} column={null} rowIdx={"1"} />
},
{
key: "DetailView",
name: "Detail",
resizable: false,
width: 80,
editable: true,
},
{
key: "CommentView",
name: "Comment",
resizable: false,
width: 80,
editable: true,
}
]
};
}
componentDidMount() {
this.props.defectViewActions.loadViewColumns();
}
componentWillReceiveProps(nextProps) {
if ((!this.props.viewColumns || this.props.viewColumns.length === 0) && (nextProps.viewColumns || nextProps.viewColumns.length > 0)) {
nextProps.viewColumns.forEach(function (col) {
col.SummaryView = false, col.DetailView = false, col.CommentView = false;
switch (col.DefaultView) {
case 1:
col.SummaryView = true;
break;
case 2:
col.DetailView = true;
break;
case 3:
col.CommentView = true;
break;
}
});
this.setState({
viewColumns: nextProps.viewColumns
})
;
}
}
onCellChanged() {
console.log("Cell updated");
}
// -- React Data Grid ----------------------------------------------------------------------------------------------------------
rowGetter(i) {
if (this.state.viewColumns.length > 0) {
return {
value: this.state.viewColumns[i]
};
}
else {
return "";
}
}
// -----------------------------------------------------------------------------------------------------------------------------
setReportingArea(event) {
this.props.actions.setPreferredReportingArea(event.target.value);
}
render() {
return (
<div style={{marginTop: '50px'}}>
<table className="table table-condensed" style={{width: '70%', margin: 'auto'}}>
<thead>
<tr>
<th colSpan="3"><h2>User Profile</h2></th>
</tr>
</thead>
<tbody>
<tr>
<td>Name:</td>
<td>{this.props.user.name}</td>
</tr>
<tr>
<td>Email:</td>
<td>
{this.props.user.Username}
</td>
</tr>
<tr>
<td>Preferred Reporting Area:</td>
<td>
{(this.props.user.ReportingArea) ? (
<MultiSelectBox name="ddlReportingArea"
onChange={this.setReportingArea}
value={this.props.user.ReportingAreaId}
options={this.props.user.ReportingAreas.map((ra) => {
return {id: ra.Id, value: ra.ReportingAreaName};
}).sort((a, b) => {
return a.value > b.value;
})}/>)
: "None Assigned"}
</td>
</tr>
</tbody>
</table>
<div className="row" style={{width: '70%', margin: 'auto'}}>
<div className="form-horizontal form-group">
<label className="col-md-2 control-label">View:</label>
<div className="col-md-2">
<select className="form-control">
<option>Default</option>
</select>
</div>
</div>
</div>
<div className="row" style={{width: '70%', margin: 'auto'}}>
<div className="col-md-6">
<h4>Available Columns</h4>
<ReactDataGrid
rowHeight={35}
minHeight={500}
minWidth={450}
maxWidth={450}
columns={this.state.columns}
rowGetter={this.rowGetter}
rowsCount={this.state.viewColumns.length}/>
</div>
<div className="col-md-2">
<h4>Default Columns</h4>
</div>
<div className="col-md-2">
<h4>Detail Columns</h4>
</div>
<div className="col-md-2">
<h4>History Columns</h4>
</div>
</div>
</div>
);
}
}
UserProfilePage.propTypes = {
user: PropTypes.object.isRequired,
viewColumns: PropTypes.array.isRequired,
defectViewActions: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired
};
function mapStoreStateToProps(state, ownProps) {
return {
user: state.Identity,
viewColumns: state.ViewColumns
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(identityActions, dispatch),
defectViewActions: bindActionCreators(defectViewActions, dispatch)
};
}
export default connect(mapStoreStateToProps, mapDispatchToProps)(UserProfilePage);
From the documentation is presume "value" is returned by the "rowGetter" but how do I pass the "key" and "onCellChange" props to the CheckboxEditor and is "rowIdx" obtained from "this.state.viewColumns".
Any examples or tutorials would be greatly appreciated.

Resources