Can the following class component be converted into a function component by any chance?
The main issue I'm having is inside the following cellsrenderer function
cellsrenderer: (row, columnfield, value, defaulthtml, columnproperties): string => {
axios
.get("api/personnels/"+value)
.then(response => {
this.setState({
createdByName: response.data.displayedValues
}, ()=> {
console.log('Inside axios response after setting the state to the name of the project creater')
})
}).catch(err => console.log(err));
return this.state.createdByName;
}
}
I am running into an issue of infinite loop because of setState re-rendering issue and want to avoid it by using useEffect() hook maybe if I could but since this is a class component, I am not able to proceed forward.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {FormikApp} from './forms/AddProjectForm'
import JqxGrid, {IGridProps, jqx} from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxgrid';
import JqxButton from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons'
import {RouteComponentProps} from 'react-router-dom'
import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css'
import 'jqwidgets-scripts/jqwidgets/styles/jqx.material.css'
import 'jqwidgets-scripts/jqwidgets/styles/jqx.arctic.css'
import {Dialog} from "primereact/dialog";
import {Button} from "primereact/button";
import {properties} from "../properties";
import {Card} from "primereact/card";
import axios from "axios";
import {Messages} from "primereact/messages";
import _ from 'lodash'
export interface IState extends IGridProps {
projects: [],
selectedProject: [],
createdByName :string,
addDialogVisible: boolean,
blazerId: string,
username: string,
selectedRowIndex: number,
deleteDialogVisible: boolean
}
class Projects extends React.PureComponent<RouteComponentProps<{}>, IState> {
private baseUrl = properties.baseUrlWs
private myGrid = React.createRef<JqxGrid>()
private messages = React.createRef<Messages>()
private editrow: number = -1;
constructor(props: RouteComponentProps) {
super(props);
this.selectionInfo = this.selectionInfo.bind(this)
this.gridOnSort = this.gridOnSort.bind(this);
const columns: IGridProps['columns'] = [
{ text: 'Project Name', datafield: 'name', width: 390 },
{ text: 'Project Description', datafield: 'description', width: 390 },
{ text: 'Owner Assigned', datafield: 'institutionId', width: 180,hidden:true },
{ text: 'Created By', datafield: 'createdBy',
cellsrenderer: (row, columnfield, value, defaulthtml, columnproperties): string => {
axios
.get("api/personnels/"+value)
.then(response => {
this.setState({
createdByName: response.data.displayedValues
}, ()=> {
console.log('Inside axios response after setting the state to the name of the project creater')
})
}).catch(err => console.log(err));
return this.state.createdByName;
}
}
]
const source:any = {
dataFields: [
{ name: 'id', type: 'long'},
{ name: 'name', type: 'string' },
{ name: 'description', type: 'string' },
{ name: 'url', type: 'string'},
{ name: 'irbProtocol', type: 'string'},
{ name: 'institutionId', type: 'long' },
{ name: 'projectType', type: 'string' },
{ name: 'priority', type: 'string'},
{ name: 'researchDataSetType', type: 'string'},
{ name: 'statusIndicatorId', type: 'long'},
{ name: 'createdBy', type: 'string' }
],
dataType: 'json',
root: 'projects',
sortColumn: 'name',
sortdirection: 'asc',
url: this.baseUrl + 'api/projects/search/getProjectsById',
data: {
value: ''
}
}
const dataAdapter:any = new jqx.dataAdapter(source,
{
autoBind: true,
downloadComplete: (data:any, status:any, xhr:any):void => {
// if (!source.totalrecords) {
source.totalrecords = parseInt(data['page'].totalElements);
// }
},
formatData: (data:any):any => {
data.page = data.pagenum
data.size = data.pagesize
if (data.sortdatafield && data.sortorder) {
data.sort = data.sortdatafield + ',' + data.sortorder;
}
return data;
},
loadError (xhr, status, error) {
throw new Error('Error occurred in getting Projects for user ' + error.toString());
}
}
);
this.state = {
projects: [],
selectedProject: [],
createdByName : '',
blazerId: '',
username: '',
addDialogVisible: false,
selectedRowIndex: null,
deleteDialogVisible: false,
columns: columns,
rendergridrows: (params: any): any[] => {
const data = params.data
return data;
},
source: dataAdapter,
};
}
setValueProperty = (data:any):any => {
if (this.state && this.state.blazerId) {
data.value = this.state.blazerId
}
}
private gridOnSort(event: any): void {
const sortinformation = event.args.sortinformation;
let sortdirection = sortinformation.sortdirection.ascending ? 'ascending' : 'descending';
if (!sortinformation.sortdirection.ascending && !sortinformation.sortdirection.descending) {
sortdirection = 'null';
}
this.myGrid.current.updatebounddata('sort')
};
selectionInfo = (event: any): void => {
const selection = this.myGrid.current.getrowdata(event.args.rowindex)
this.setState({
selectedProject: selection
}, () => {
console.log('pushing ' + this.state.selectedProject)
this.props.history.push({
pathname: '/project',
state: {
project: this.state.selectedProject,
blazerId: this.state.blazerId
}
})
});
}
componentDidMount() {
console.log('In Projects.componentDidMount....' + sessionStorage.getItem('loggedInUser'))
if (sessionStorage.getItem('loggedInUser') != null) {
const loggedInUser = JSON.parse(sessionStorage.getItem('loggedInUser') as string)
this.setState({ employeeId: loggedInUser.employeeId})
}
}
render() {
const defaultView = this.state.addDialogVisible ? null : (this.state.employeeId && !_.isEmpty(this.state.employeeId)) ? (
<div style={{width: '100%', margin: '0 auto', display: 'table'}}>
<JqxGrid
// #ts-ignore
ref={this.myGrid}
theme={'arctic'}
altrows={true}
width="100%"
autoheight={true}
source={this.state.source}
columns={this.state.columns}
pageable={true}
sortable={true}
onSort={this.gridOnSort}
pagesize={20}
virtualmode={true}
rendergridrows={this.state.rendergridrows}
showtoolbar={true}
rendertoolbar={this.state.rendertoolbar}
columnsresize={true}/>
</div>
) : null
return (
<div className="project-page-main">
<Messages ref={this.messages} style={{width: '100%', margin: 'auto' }}/>
<div className="content">
{defaultView}
</div>
</div>
);
}
}
export default Projects;
Related
I am recently developing an email list using React Table.
There is a BCC field that allows users to insert an email address.
I have implemented App.tsx as the Root component and EmailForm.tsx as the child one.
After every action from Child (Insert characters in BCC, select the checkboxes), an update email list is sent from the Child to Parent component where all main activities will be handled.
I am facing a problem that every time I try to insert a new character in BCC input, "onChange" event just takes one character and not the whole input text area.
I followed this thread, but it did not help.
My repo:
https://codesandbox.io/s/thirsty-ellis-2981iv
My Parent component: App.tsx
import React, { Component } from "react";
import { Formik } from "formik";
import './App.css';
import EmailForm from "./EmailForm";
interface IEmail {
"title": number;
"checkList": ICheckList[];
"bcc": IBcc;
}
interface ICheckList {
"isEnable": boolean;
"email": string
}
interface IBcc {
"isEnable": boolean;
"email": string
}
const defaults = [
{
title: "title-1",
checkList: [{
isEnable: true,
email: "title-1.1#mail.com"
},
{
isEnable: true,
email: "title-1.2#mail.com"
}],
bcc: {
isEnable: true,
email: ""
}
},
{
title: "title-2",
checkList: [{
isEnable: true,
email: "title-2#mail.com"
}],
bcc: {
isEnable: true,
email: ""
}
},
{
title: "title-3",
checkList: [{
isEnable: true,
email: "title-3#mail.com"
}],
bcc: {
isEnable: true,
email: ""
}
}
];
class App extends Component {
state = {
data: defaults,
}
getInitialValues = () => {
const initialValues = {
...defaults
};
return initialValues;
}
handleBccInput = (index: number, event: string) => {
console.log('handleBccInput index: ' + index + ' bccInput : ' + event)
let data = [...this.state.data];
//console.log('data: ' + JSON.stringify(data));
data[index].bcc.email = event;
console.log('data[index].bcc.email: ' + data[index].bcc.email);
this.setState({ data });
}
onSubmit = () => {
console.log('onSubmit clicked')
}
handleCheckboxSelected = (emailIdx: number, addressIdx: number) => {
let data = [...this.state.data];
data[emailIdx].checkList[addressIdx].isEnable = !data[emailIdx].checkList[addressIdx].isEnable
this.setState({ data });
}
render() {
const initialValues = this.getInitialValues();
const renderForm = (props: any) => (
<EmailForm
{...props}
data={this.state.data}
handleBccInput={this.handleBccInput}
handleCheckboxSelected={this.handleCheckboxSelected}
/>
);
return (
<React.Fragment >
<Formik
// tslint:disable-next-line jsx-no-lambda
render={props => renderForm(props)}
initialValues={initialValues}
onSubmit={this.onSubmit}
validateOnBlur={true}
validateOnChange={true} />
</React.Fragment>
);
}
}
export default App;
My Child component: EmailForm.tsx:
import React, { Component } from "react";
import { Form, FormikProps } from "formik";
import { WithTranslation, withTranslation } from "react-i18next";
import ReactTable, { Column } from "react-table";
import "react-table/react-table.css";
interface IEmail {
"title": number;
"checkList": ICheckList[];
"bcc": IBcc;
}
interface ICheckList {
"isEnable": boolean;
"email": string
}
interface IBcc {
"isEnable": boolean;
"email": string
}
interface IState {
data: IEmail[],
handleBccInput(index: any, event: string): any,
handleCheckboxSelected(emailIndex: number, addressIndex: number): any,
}
class EmailForm extends Component<IEmail & IState & WithTranslation> {
renderCheckbox = (title: string) => {
return (
<div>{title}</div>
);
}
overrideValue = (index: number, override: any) => {
//console.log('index: ' + index + ' override: ' + override)
this.props.handleBccInput(index, override)
}
onCheckBoxItemSelected = (emailIndex: number, addressIndex: number) => {
this.props.handleCheckboxSelected(emailIndex, addressIndex)
}
renderHeader = (title: string) => {
return (
<div
style={{
textAlign: "center",
}}
>{title}</div>
);
}
tableHeader = (): Array<Column<IEmail>> => {
// Extract transalation variable from props
return [
{
Header: this.renderHeader('Title'),
id: "title",
accessor: "title",
width: 200,
Cell: props => {
return (
<input value={props.value} readOnly></input>
)
},
},
{
Header: this.renderHeader("Check List"),
id: "checkList",
accessor: "checkList",
sortable: false,
width: 200,
resizable: true,
Cell: props => {
const cellValues = props.value
//console.log('cell.value : ' + JSON.stringify(cellValues))
return cellValues.map((item: ICheckList, index: number) => {
return (
<div>
<input type="checkbox" checked={item.isEnable} onChange={() => this.onCheckBoxItemSelected(props.index, index)} />
<a>{item.email}</a>
</div>
)
})
}
},
{
Header: this.renderHeader("BCC"),
id: "bcc",
accessor: "bcc",
Cell: props => {
return (
<input disabled={!props.value.isEnable} value={props.value.email} onChange={e => { this.overrideValue(props.index, e.target.value) }} type="text" ></input>
)
},
width: 200,
}
];
}
/*
Component render function
*/
render() {
const {
t,
data,
} = this.props
const emptyElement = () => null;
const tableHeader = this.tableHeader();
return (
<Form className="email-container-form">
<ReactTable
columns={tableHeader}
resizable={false}
data={data}
loading={false}
showPagination={false}
NoDataComponent={emptyElement}
defaultPageSize={Number.MAX_SAFE_INTEGER}
minRows={1}
/>
</Form>
)
}
}
export default withTranslation()(EmailForm);
I am using Grid.js to render a table in react. I need to extract the data in one of the cells. When I map the args, I get two results back....a MouseEvent and 'n' which contains the data that I need. How do I extract the data out of the 'n' result? Below is an image of what I receive from my current code which is below the picture.
import React, { useState, useEffect, useRef, Fragment } from 'react';
import axios from 'axios';
import { API } from '../../config';
import Layout from '../../components/Layout';
import { Grid, html, h } from 'gridjs';
import 'gridjs/dist/theme/mermaid.css';
const PendingUser = () => {
const [pendingUser, setPendingUser] = useState({});
const wrappedRef = useRef(null);
useEffect(() => {
getPendingUsers();
setPendingUser(pendingUser);
grid.render(wrappedRef.current);
}, []);
const getPendingUsers = async () => {
const { data } = await axios.get(`${API}/admin/pendinguser`);
await data.filter(user => {
user.accountApproved ? setPendingUser(user) : setPendingUser();
});
};
const handleClick = e => {
e.preventDefault();
const buttonValue = e.target.value;
console.log(buttonValue);
grid.on('rowClick', (...args) =>
args.map(data => {
console.log(data);
})
);
};
const grid = new Grid({
search: true,
columns: [
{
name: 'ID',
hidden: true
},
{
name: 'First Name'
},
{
name: 'Last Name'
},
{
name: 'Email'
},
{
name: 'Agency'
},
{
name: 'Approve',
formatter: (cell, row) => {
return h(
'button',
{
style: 'cursor: pointer',
className: 'py-2 mb-2 px-2 border rounded text-white bg-success',
value: 'approve',
onClick: e => handleClick(e, 'value')
},
'Approve'
);
}
},
{
name: 'Deny',
formatter: (cell, row) => {
return h(
'button',
{
styel: 'cursor: pointer',
className: 'py-2 mb-2 px-2 border rounded text-white bg-danger',
value: 'deny',
onClick: e => handleClick(e, 'value')
},
'Deny'
);
}
},
{
name: 'Denied Reason',
formatter: (_, row) =>
html(
'<select>' +
'<center><option value="Non Law Enforcement">Non Law Enforcement</option><option value="Non Law Enforcement">Non US Law Enforcement</option></center>' +
'</select>'
)
}
],
server: {
url: `${API}/admin/pendinguser`,
method: 'GET',
then: data =>
data.map(user => [
user._id,
user.firstName,
user.lastName,
user.email,
user.leAgency
])
}
});
return (
<Layout>
<div ref={wrappedRef} />
</Layout>
);
};
export default PendingUser;
here is what the 'n' data looks like and I have circled what I want to extract.
columns: [{ name: 'Name',
attributes: (cell) => {
// add these attributes to the td elements only
if (cell) {
return {
'data-cell-content':cell,
'onclick': () => alert(cell)
};
}
}},
This worked for me bro.
I am having a callback function which updates my array in the SetState and it works fine as I can see in the console log in the handleDaysValueChange all is good. But when I try to access it in another function i.e handleValuesChange the values are not up to date. I am missing a async or something.
import React from 'react';
import PropTypes from 'prop-types';
import AppService from 'services/app-service';
import Enum from 'enum';
import { ApiData } from 'data';
import { isEmpty, boolValue } from 'core/type-check';
import { notifySuccess } from 'core/errors';
import { withDrawerForm } from 'components/_hoc';
import { ExtendedAvatar } from 'components/extended-antd';
import { Tabs } from 'antd';
import { FormTemplateAudit } from '../templates';
import ShiftRosterFormDetails from './shiftroster-form-details';
import Item from 'antd/lib/list/Item';
const { TabPane } = Tabs;
class ShiftRosterForm extends React.Component {
constructor(props) {
super(props);
this.formInputRef = React.createRef();
this.state = {
daysValue:[]
};
this.handleDaysValueChange = this.handleDaysValueChange.bind(this);
}
handleDaysValueChange(daysValues) {
this.setState({ daysValue: daysValues }, () => {
console.log("Data" + this.props.customData);
console.log("Hello World " + JSON.stringify(this.state.daysValue));
});
}
componentDidMount() {
// Update the parent form state with a reference to the
// formInputRef so we can call this later for validation
// before saving the data to the server.
const { onFormStateChange } = this.props;
onFormStateChange({ formInputRef: this.formInputRef.current });
}
//Shift Roster Detail
handleValuesChange = (props, changedValues, allValues) => {
// Update the parent form state with the changed item
// details and mark the form as dirty
const { itemData, onFormStateChange } = this.props;
console.log("Hey" + this.state.daysValue);
onFormStateChange({
isFormDirty: true,
itemData: {
...itemData,
...changedValues,
...this.state.daysValue
}
});
}
render() {
const { itemData, customData } = this.props;
const isSR = (!isEmpty(itemData) && itemData.id > 0);
return (
<Tabs className="bhp-tabs" defaultActiveKey="1" animated={false}>
<TabPane key="1" tab="Details">
<ShiftRosterFormDetails
ref={this.formInputRef}
dataSource={itemData}
onValuesChange={this.handleValuesChange}
handleDaysValueChange={this.handleDaysValueChange}
/>
</TabPane>
<TabPane key="2" tab="Audit" disabled={!isSR}>
<FormTemplateAudit
itemData={itemData}
/>
</TabPane>
</Tabs>
);
}
}
ShiftRosterForm.propTypes = {
itemId: PropTypes.number, // Passed in by the HOC. The loaded Shift Roster id
itemData: PropTypes.object, // Passed in by the HOC. The loaded Shift Roster data
customData: PropTypes.object, // Temporary store to hold the changed Shift Roster
isFormDirty: PropTypes.bool, // Passed in by the HOC. Flags if the parent form is dirty
isLoading: PropTypes.bool, // Passed in by the HOC. Flags if the parent form is loading
daysValue: PropTypes.object,
onFormStateChange: PropTypes.func // Passed in by the HOC. Callback to update the parent form state.
};
ShiftRosterForm.defaultProps = {
itemId: -1,
itemData: {},
customData: {},
isFormDirty: false,
isLoading: false,
daysValue: {},
onFormStateChange() { }
};
const ShiftRosterFormTitle = ({ data }) => {
const name = (!isEmpty(data) && data.id > 0) ? `${data.name}` : 'New Shift Roster';//`${data.name}`
return isEmpty(data)
? <ExtendedAvatar type="icon" size="large" />
: <span><ExtendedAvatar name={name} type="letter" size="large" />{name}</span>
}
const saveShiftRoster = (shiftrosterId, shiftroster, rosterdays) => {
return ApiData.saveShiftRoster(shiftrosterId, shiftroster, rosterdays)
.then(response => {
notifySuccess('Save Successful', 'Site Work Package saved successfully');
return response;
})
.catch(error => {
throw error;
});
}
const saveForm = (formState, setFormState) => {
const { isFormDirty, itemData, customData, formInputRef } = formState;
const typeName = "Dynamic";
const actualType = itemData.type;
let rosterdays = [];
if (actualType !== typeName) {
rosterdays = GetDaysForRoster(itemData);
console.log("My Values" + JSON.stringify(rosterdays));
}
const shiftRosterId = itemData.id;
const isExistingShiftRoster = shiftRosterId > 0;
return new Promise((resolve, reject) => {
if (isExistingShiftRoster && !isFormDirty) {
// No Changes
notifySuccess('Save Successful', 'Site Work Package saved successfully');
resolve(itemData);
}
else {
// Validate and Save
formInputRef.validateFields((error, values) => {
if (!error) {
// Form validated successfully.
// Save form changes
const shiftrosterRecord = saveShiftRoster(shiftRosterId, values, rosterdays);
resolve(shiftrosterRecord);
}
else {
// Form validation error.
// Return data as is.
resolve(itemData);
}
});
}
});
}
const GetDaysForRoster = (itemsData) => {
const result = [];
const keys = Object.keys(itemsData);
for (const k in keys) {
if (Number(k) == k) {
result[k] = itemsData[k]
}
}
return result.filter(function (el) { return el != null });
}
const WrappedShiftRosterForm = withDrawerForm({
containerClassName: 'bhp-equipment-type-form',
title: (record) => <ShiftRosterFormTitle data={record} />,
onLoad: (itemId, setFormState) => ApiData.getShiftRoster(itemId),
onSave: (formState, setFormState) => { return saveForm(formState, setFormState); },
canView: () => AppService.hasAccess({ [Enum.SecurityModule.EquipmentTypeDetails]: [Enum.SecurityPermission.Read] }),
canCreate: () => AppService.hasAccess({ [Enum.SecurityModule.EquipmentTypeDetails]: [Enum.SecurityPermission.Create] }),
canUpdate: () => AppService.hasAccess({ [Enum.SecurityModule.EquipmentTypeDetails]: [Enum.SecurityPermission.Update] })
})(ShiftRosterForm);
WrappedShiftRosterForm.propTypes = {
containerClassName: PropTypes.string,
itemId: PropTypes.number,
visible: PropTypes.bool,
onSave: PropTypes.func,
onClose: PropTypes.func
};
WrappedShiftRosterForm.defaultProps = {
containerClassName: null,
itemId: -1,
visible: false,
onSave() { },
onClose() { }
};
export default WrappedShiftRosterForm;
//ShiftRosterFormDetails
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { ApiData } from 'data';
import { Form, Input, Select, Button, space, InputNumber } from 'antd';
import ShiftDays from './shiftdays'
const ShiftRosterFormDetails = ({ form, dataSource, onValueChange, handleDaysValueChange }) => {
const { getFieldDecorator } = form;
const formLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 },
},
};
console.log("My datasource" + dataSource.shiftRosterDays);
//const daysRoster = dataSource.shiftRosterDays || [{ daysIn: 1, daysOut: 1, category: "Day Shift" }];
const [inputList, setInputList] = useState([{ daysIn: 1, daysOut: 1, category: "Day Shift" }]);
const [selectedType, setSelectedType] = useState(dataSource.type || 'Fixed Single');
const [isTotalDaysRequired, SetTotalDaysRequired] = useState(dataSource.type === 'Dynamic' ? true : false);
const [isTotalDaysRequiredMessage, setIsTotalDaysRequiredMessage] = useState(dataSource.type === 'Dynamic' ? 'Please enter the Total Days' : '');
const handleTypeChanged = (value, e) => {
setSelectedType(value);
if (value === "Dynamic") {
SetTotalDaysRequired(true);
setIsTotalDaysRequiredMessage('Please enter the Total Days');
}
if (value === "Fixed Single") {
if (inputList.length > 1) {
const list = [...inputList];
console.log("Total" + inputList.length);
list.splice(1, inputList.length);
setInputList(list);
console.log("My List" + JSON.stringify(list));
console.log("Input List" + JSON.stringify(inputList));
handleDaysValueChange(list);
}
}
else {
SetTotalDaysRequired(false);
setIsTotalDaysRequiredMessage('');
}
};
return (
<div className='bhp-equipment-type-form-details bhp-content-box-shadow'>
<Form {...formLayout}>
<Form.Item label='Name' hasFeedback>
{getFieldDecorator('name', {
initialValue: dataSource.name,
rules: [{
required: true,
message: 'Please enter the Name'
}],
})(
//disabled={dataSource.id > 0}
<Input placeholder='Name' />
)}
</Form.Item>
<Form.Item label='Status' hasFeedback>
{getFieldDecorator('status', {
initialValue: dataSource.status,
rules: [{
required: true,
message: 'Please enter the Status'
}],
})(
<Select>
<Select.Option value="Active">Active</Select.Option>
<Select.Option value="InActive">InActive</Select.Option>
</Select>
)}
</Form.Item>
<Form.Item label='Type' hasFeedback>
{getFieldDecorator('type', {
initialValue: dataSource.type || 'Fixed Single',
rules: [{
required: true,
message: 'Please select the Type'
}],
})(
<Select onChange={handleTypeChanged}>
<Select.Option value="Fixed Single">Fixed Single</Select.Option>
<Select.Option value="Fixed Multiple">Fixed Multiple</Select.Option>
<Select.Option value="Dynamic">Dynamic</Select.Option>
</Select>
)}
</Form.Item>
<Form.Item label='Total Days' hasFeedback style={selectedType === 'Dynamic' ? { display: '' } : { display: 'none' }}>
{getFieldDecorator('totaldays', {
initialValue: dataSource.totalDays,
rules: [{
required: isTotalDaysRequired,
message: isTotalDaysRequiredMessage
}],
})(
<InputNumber min={1} max={365} />
)}
</Form.Item>
<ShiftDays inputList={inputList} setInputList={setInputList} selectedType={selectedType} handleDaysValueChange={handleDaysValueChange} getFieldDecorator={getFieldDecorator} />
</Form>
</div>
)};
const onFieldsChange = (props, changedFields, allFields) => {
if (props.onFieldsChange) {
props.onFieldsChange(props, changedFields, allFields);
}
};
const onValuesChange = (props, changedValues, allValues) => {
if (props.onValuesChange) {
props.onValuesChange(props, changedValues, allValues);
}
};
ShiftRosterFormDetails.propTypes = {
form: PropTypes.object,
dataSource: PropTypes.object,
onFieldsChange: PropTypes.func,
onValuesChange: PropTypes.func
};
ShiftRosterFormDetails.defaultProps = {
form: {},
dataSource: {},
onFieldsChange() { },
onValuesChange() { }
};
export default Form.create({
onValuesChange,
onFieldsChange
})(ShiftRosterFormDetails);
I have a highcharts function that populates a chart. It also has a drilldown event that needs to be called when the drilldown event is triggered.
I get this following error when I drilldown the charts-
TypeError: this.filter_data is not a function
The drilldown event is in the populate_group_by_gender_chart function under the options/chart/events.
import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Container, } from 'react-bootstrap';
import Header from './Components/Header';
import Wrapper from './Components/Wrapper';
import _ from 'lodash';
import './App.css';
let county_data = 'https://data.m.gov/api/views/kdqy-4wzv/rows.json?accessType=DOWNLOAD'
class App extends Component {
constructor(props){
super(props)
this.state = {
raw_data: [],
employee_data: [],
column_names: [],
page_num: 1,
group_by_gender_data: {}
}
}
componentDidMount = () => {
this.fetchData();
}
fetchData = async () => {
fetch(county_data).
then(response => response.json()).
then(response => {
// console.log(response.data)
let column_names = _.map(response.meta.view.columns, 'name')
const data_map = response.data.map(data=> {
return {
id: data[0],
'full_name':data[8],
'gender':data[9],
'current_annual_salary':data[10],
'2018_gross_pay_received':data[11],
'2018_overtime_pay':data[12],
'department':data[13],
'department_name':data[14],
'division':data[15],
'assignment_category':data[16],
'employee_position_title':data[17],
'position_under_filled':data[18],
'date_first_hired':data[19]
}
})
// console.log('data_map - ', data_map)
let grouped_data_by_chunks = _.chunk(data_map, data_map.length/100)
// console.log('grouped_data -', grouped_data_by_chunks)
this.setState({
raw_data: data_map,
employee_data: grouped_data_by_chunks[0],
column_names: column_names
})
this.populate_group_by_gender_chart(data_map);
})
}
populate_group_by_gender_chart = (data) => {
console.log('drilldown this.filter_data -', this.filter_data)
var options = {
chart: {
type: "pie",
events:{
drilldown: function(e){
console.log('e.point.name - ', e.point.name)
var filter_by = (e.point.name = 'Female') ? 'F': 'M'
this.filter_data('GENDER', data, filter_by)
}
}
},
title: {
text: 'Employees by Gender'
},
series: [
{
name: 'Gender',
data: []
}
],
plotOptions: {
series: {
cursor: 'pointer',
point: {}
},
},
};
options.series[0].data = this.filter_data('GENDER', data)
this.setState({
group_by_gender_options: options
})
}
filter_data = (filter, data, filter_by) => {
if (filter == 'GENDER'){
data = _.map(data, 'gender')
data = _.filter(data, function(val){
return val == 'F';
})
const result = _.values(_.groupBy(data)).map(d => ({'y' : d.length,
'name' : d[0] == 'F' ? 'Female': 'Male',
'id': d[0] == 'F' ? 'F': 'M',
'drilldown': true
}));
return result
}
}
render() {
return (
<div className="App">
<Container fluid={true}>
<Header/>
<Wrapper data={this.state.employee_data}
group_by_gender_chart_data={this.state.group_by_gender_options}
></Wrapper>
</Container>
</div>
);
}
}
export default App;
I am trying to follow this page sample:
https://ant.design/components/table/
The antd filtering sample to be precise
I have a column which I know its 2 possible values only.
I can see in the debugger that the handlechange event is executed, but after click OK in the filter, the table is not filtered as it should
My best guess I am missing something on the OnFilter event
import React, { Component } from 'react';
import { Table, Tag, Button} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';
class ListPageTemplatesWithSelection extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
filteredInfo: null,
sortedInfo: null,
};
this.handleChange= this.handleChange.bind(this);
this.clearFilters= this.clearFilters.bind(this);
this.clearAll= this.clearAll.bind(this);
}
handleChange(pagination, filters, sorter){
console.log('Various parameters', pagination, filters, sorter);
this.setState({
filteredInfo: filters,
sortedInfo: sorter,
});
}
clearFilters(){
this.setState({ filteredInfo: null });
}
clearAll(){
this.setState({
filteredInfo: null,
sortedInfo: null,
});
}
fetchData = () => {
adalApiFetch(fetch, "/PageTemplates", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
const results= responseJson.map(row => ({
key: row.Id,
Name: row.Name,
SiteType: row.SiteType,
Tags: row.Tags
}))
this.setState({ data: results });
}
})
.catch(error => {
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render(){
let { sortedInfo, filteredInfo } = this.state;
sortedInfo = sortedInfo || {};
filteredInfo = filteredInfo || {};
const columns = [
{
title: 'Id',
dataIndex: 'key',
key: 'key',
},
{
title: 'Name',
dataIndex: 'Name',
key: 'Name',
},
{
title: 'Site Type',
dataIndex: 'SiteType',
key: 'SiteType',
filters: [
{ text: 'Modern Team Site', value: 'Modern Team Site' },
{ text: 'CommunicationSite', value: 'CommunicationSite' },
],
filteredValue: filteredInfo.name || null,
onFilter: (value, record) => record.Tags.includes(value),
},{
title: 'Tags',
key: 'Tags',
dataIndex: 'Tags',
render: Tags => (
<span>
{Tags && Tags.map(tag => {
let color = tag.length > 5 ? 'geekblue' : 'green';
if (tag === 'loser') {
color = 'volcano';
}
return <Tag color={color} key={tag}>{tag.toUpperCase()}</Tag>;
})}
</span>
),
}
];
const rowSelection = {
selectedRowKeys: this.props.selectedRows,
onChange: (selectedRowKeys) => {
this.props.onRowSelect(selectedRowKeys);
}
};
return (
<div>
<Button onClick={this.clearFilters}>Clear filters</Button>
<Button onClick={this.clearAll}>Clear filters and sorters</Button>
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} onChange={this.handleChange} />
</div>
);
}
}
export default ListPageTemplatesWithSelection;
In your SiteType column, you have mistakenly set filteredValue prop to filteredInfo.name. But the filter is not on a name column, it is on SiteType column.
Change this line from:
filteredValue: filteredInfo.name || null,
To:
filteredValue: filteredInfo.SiteType || null,
And it should be fine.
You need execute the fetchData function in the handleChange function. Add filter params to ajax request. Just like this:
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
}