How to import useCombinedRefs when using react-data-grid - reactjs

I am trying to implement the draggable columns with react-data-grid based on this example: https://github.com/adazzle/react-data-grid/blob/canary/stories/demos/ColumnsReordering.tsx
I see that this example requires creating a DraggableHeaderRenderer file, so I have copied the following file into my project and converted it to React: https://github.com/adazzle/react-data-grid/blob/canary/stories/demos/components/HeaderRenderers/DraggableHeaderRenderer.tsx
My issue is that I do not know where to import useCombinedRefs from. It is not exported from react-data-grid. I see in the repo that it resides in src/hooks.
I have tried the following:
import {useCombinedRefs} from 'react-data-grid'
// Error: Attempted import error: 'useCombinedRefs' is not exported from 'react-data-grid'.
import {useCombinedRefs} from 'react-data-grid/lib/hooks';
// Error: Module not found: Can't resolve 'react-data-grid/lib/hooks' in 'C:\Users\Liam\Desktop\Work\MyProject\src\ReactDataGrid'
import useCombinedRefs from 'react-data-grid/lib/hooks/useCombinedRefs';
// Error: Module not found: Can't resolve 'react-data-grid/lib/hooks/useCombinedRefs' in 'C:\Users\Liam\Desktop\Work\MyProject\src\ReactDataGrid'
Thanks to anyone who can help.
Here is my code:
DraggableHeaderRenderer.js
import { useDrag, useDrop } from 'react-dnd';
import React from 'react'
import { SortableHeaderCell } from 'react-data-grid';
import useCombinedRefs from 'react-data-grid/lib/hooks/useCombinedRefs';
export function DraggableHeaderRenderer({ onColumnsReorder, column, sortColumn, sortDirection, onSort }) {
const [{ isDragging }, drag] = useDrag({
item: { key: column.key, type: 'COLUMN_DRAG' },
collect: monitor => ({
isDragging: !!monitor.isDragging()
})
});
const [{ isOver }, drop] = useDrop({
accept: 'COLUMN_DRAG',
drop({ key, type }) {
if (type === 'COLUMN_DRAG') {
onColumnsReorder(key, column.key);
}
},
collect: monitor => ({
isOver: !!monitor.isOver(),
canDrop: !!monitor.canDrop()
})
});
return (
<div
ref={useCombinedRefs(drag, drop)}
style={{
opacity: isDragging ? 0.5 : 1,
backgroundColor: isOver ? '#ececec' : 'inherit',
cursor: 'move'
}}
>
<SortableHeaderCell
column={column}
sortColumn={sortColumn}
sortDirection={sortDirection}
onSort={onSort}
>
{column.name}
</SortableHeaderCell>
</div>
);
}
TestDataGrid.js
import React from 'react';
import DataGrid from 'react-data-grid';
import {DraggableHeaderRenderer} from './DraggableHeaderRenderer';
import { useState, useCallback, useMemo } from 'react';
import 'react-data-grid/dist/react-data-grid.css';
const createRows = () => {
const rows = [];
for (let i = 1; i < 500; i++) {
rows.push({
id: i,
task: `Task ${i}`,
complete: Math.min(100, Math.round(Math.random() * 110)),
priority: ['Critical', 'High', 'Medium', 'Low'][Math.round(Math.random() * 3)],
issueType: ['Bug', 'Improvement', 'Epic', 'Story'][Math.round(Math.random() * 3)]
});
}
return rows;
}
const createColumns = () => {
return [
{
key: 'id',
name: 'ID',
width: 80,
},
{
key: 'task',
name: 'Title',
resizable: true,
sortable: true,
draggable: true
},
{
key: 'priority',
name: 'Priority',
resizable: true,
sortable: true,
draggable: true
},
{
key: 'issueType',
name: 'Issue Type',
resizable: true,
sortable: true,
draggable: true
},
{
key: 'complete',
name: '% Complete',
resizable: true,
sortable: true,
draggable: true
}
];
}
export default function TestDataGrid() {
const [rows] = useState(createRows)
const [columns, setColumns] = useState(createColumns)
const draggableColumns = useMemo(() => {
const HeaderRenderer = (props) => {
return <DraggableHeaderRenderer {...props} onColumnsReorder={handleColumnsReorder}/>
}
const handleColumnsReorder = (sourceKey, targetKey) => {
const sourceColumnIndex = columns.findIndex(c => c.key === sourceKey);
const targetColumnIndex = columns.findIndex(c => c.key === targetKey);
const reorderedColumns = [...columns];
reorderedColumns.splice(
targetColumnIndex,
0,
reorderedColumns.splice(sourceColumnIndex, 1)[0]
);
setColumns(reorderedColumns);
}
return columns.map(c => {
if(c.key === "id") return c;
return {...c, HeaderRenderer}
});
}, [columns])
return (
<DataGrid
columns={draggableColumns}
rows={rows}
/>
);
}

Related

update options without reseting the zoom

I am using React ApexChart in order to show off some data, and I have a switch that shows and hides the data labels. The options are changing without problems, but the zoom level is resetting every time. Is there a way to keep the zoom level when changing the options?
Here is a small preview of the component:
import Chart from "react-apexcharts";
import React, { useEffect, useState } from 'react';
import { Layout } from "antd";
interface Props {
series?: ApexAxisChartSeries;
chartOptiosn?: Record<string, any>;
[ key: string ]: any;
}
export const DynamicChart: React.FC<Props> = React.memo( ( props: Props ) => {
const { Content } = Layout;
const { series, chartOptions, uuid } = props;
const [ initialRerender, setInitialRerender ] = useState( false );
useEffect( () => {
if ( !initialRerender ) {
setInitialRerender( true );
}
}, [ initialRerender ] );
useEffect( () => {
}, [] );
useEffect( () => {
console.log( chartOptions );
}, [ chartOptions ] );
return (
<Layout>
<Content>
<Chart
options={ { ...structuredClone( chartOptions || {} ), chart: { ...chartOptions.chart, id: uuid } } }
series={ series }
type="area"
height={ 350 }
/>
</Content>
</Layout>
);
} );
Here are the options:
export const defaultOptions: ApexCharts.ApexOptions = {
series: [],
chart: {
animations: {
enabled: true,
easing: "linear",
dynamicAnimation: {
speed: 300
}
},
toolbar: {
show: true,
tools: {
download: `<svg viewBox="64 64 896 896" focusable: "false" name= "download" theme="outlined"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg>`,
selection: false,
zoom: true,
zoomin: true,
zoomout: true,
pan: true,
customIcons: []
},
},
zoom: {
enabled: true
}
},
dataLabels: {
enabled: false
},
yaxis: {
labels: {
style: {
fontSize: "14px",
fontWeight: 600,
colors: [ "#8c8c8c" ],
},
},
},
xaxis: {
type: "datetime"
}
};
Here is a demo for more depth of the problem that I am facing.
Just zoom in between the 3 seconds interval and after the labels reappear, the zoom is refreshed. Is there a way to stop that in react, or should I seek a vanilla approach and ditch the react solution all together?

Function does not work on first render instead the series is generated after the subsequent renders

My function generateSeriesDataWithColor() seems like it does not load before the component or page renders.
So, the seriesWithColor should get the data genrated by generateSeriesDataWithColor() right away when the component is loaded but it does not get generated at the first render, instead if the component is rendered again, the colors and the graph shows up.
import HighchartsReact from "highcharts-react-official";
import Highcharts from "highcharts";
import './SkillsGraph.scss';
import { Col, Row } from "react-bootstrap";
import HeadingMain from "../../Heading/HeadingMain/HeadingMain";
export default function SkillsGraph(){
const skills = ['HTML5/CSS3/JS', 'Java11', 'PHP', 'MySql', 'MongoDB', 'ReactJS', 'ExpressJS'];
const series = {
name: 'Skill Level',
data: [ 10, 9.5, 7, 9.5, 8, 8.5, 8]
};
const seriesWithColor = generateSeriesDataWithColor(series); // This is where the series is assigned to the var
// Randomly generate colors
function generateRandomColor(){
let maxVal = 0xFFFFFF; // 16777215
let randomNumber = Math.random() * maxVal;
randomNumber = Math.floor(randomNumber);
randomNumber = randomNumber.toString(16);
let randColor = randomNumber.padStart(6, 0);
return `#${randColor.toUpperCase()}`
}
// Generate the data with random conlor
function generateSeriesDataWithColor(seriesData){
const data = seriesData.data;
const dataArray = data.map((item) => {
let color = generateRandomColor();
while(color === "#FFFFFF"){
color = generateRandomColor();
}
let dataObj = {
y: item,
color: color
}
return dataObj;
})
let seriesWithColor = {
name: 'Skill Level',
data: dataArray
}
return seriesWithColor; //This is from where the data/series is returned
}
// Options for the graph
let options = {
chart: {
type: 'bar',
height: 400
},
title: {
align: 'left',
text: 'Skills represented'
},
xAxis: {
categories: skills,
visible: true,
type: 'Skills categorised',
title: {
text: null
}
},
yAxis: {
min: 0,
max: 10,
title: {
text: 'Skill Level',
align: 'high'
},
labels: {
overflow: 'justify'
}
},
plotOptions: {
bar: {
dataLabels: {
enabled: false
}
},
column: {
colorByPoint: true
}
},
colors: [
'#ff0000',
'#00ff00',
'#0000ff',
'#0000ff',
'#0000ff',
'#0000ff',
'#0000ff'
],
legend: {
enabled: true
},
credits: {
enabled: false
},
series: seriesWithColor // This is where the generated data/series is used
}
return (
<Row>
<Col md={3}>
<HeadingMain name="This is Legend"></HeadingMain>
</Col>
<Col md={9}>
<HighchartsReact highcharts={Highcharts} options={options} className="chart"></HighchartsReact>
</Col>
</Row>
)
}
Does anyone have a solution for this?
I tried using useEffect hook to complete the wanted task but it gives an error message - 'React Hook useEffect has missing dependencies: 'generateSeriesDataWithColor' and 'series'. Either include them or remove the dependency array react-hooks/exhaustive-deps'. (Please check the code below)
const [seriesWithColor, setSeries] = useState(null);
useEffect(() => {
generateSeriesDataWithColor(series)
.then(data => setSeries(data))
.catch(err => console.log(err));
}, []);
Series needs to be an array of objects instead of a single object:
let options = {
...,
series: [seriesWithColor] // This is where the generated data/series is used
};
Live demo: https://codesandbox.io/s/highcharts-react-demo-h4r493?file=/demo.jsx
API Reference: https://api.highcharts.com/highcharts/series
You will need to call the function within useEffect hook to make sure that the data is available.

What am I doing wrong with the ag-grid in react?

I'm trying to make the the ag-grid group selectable if say for example we have the care maker and you can select the parent and everything underneath that parent also gets selected.
I've looked into the ag-grid documentation but it looks like I'm doing everything right.
Here's my code below:
import React, { useState } from 'react';
import { AgGridReact, AgGridColumn } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-balham.css';
const DummyGrid = () => {
const [gridApi, setGridApi] = useState(null);
const columnDefs = [
{
headerName: 'Make', field: 'make', checkboxSelection: true , rowGroup: true, groupSelectsChildren: true
},
{
headerName: 'Model', field: 'model'
},
{
headerName: 'Price', field: 'price'
}
]
const onGridReady = (params) => {
setGridApi(params.api);
}
const rowData = [
{ make: 'Honda', model: 'Chev', price: 6000 },
{ make: 'Honda', model: 'Civic', price: 120000 },
{ make: 'Toyota', model: 'Celica', price: 5000 },
{ make: 'Mitsubishi', model: 'GTR', price: 5000 }
]
const handleClick = () => {
const selectedNodes = gridApi.getSelectedNodes();
const selectedData = selectedNodes.map(node => node.data);
const selectedDataStringRepresentation = selectedData.map(node => node.make + ' ' + node.model).join(', ');
console.log(`The Data selected: ${selectedDataStringRepresentation}`);
}
return(
<div className="ag-theme-balham"
style={{
width: 600,
height: 600
}}>
<button onClick={handleClick}>Click this!</button>
<AgGridReact
rowData = {rowData}
columnDefs={columnDefs}
rowSelection="multiple"
onGridReady={onGridReady}
/>
</div>
);
};
export default DummyGrid;
As you can see from the output below that they're not grouping even though they the same maker. What am I doing wrong?
2 things you're doing wrong.
First, you need to import the RowGroupingModule module and pass it to your grid as modules:
import { RowGroupingModule } from '#ag-grid-enterprise/row-grouping';
modules={[RowGroupingModule]}
Secondly, you need to set groupSelectsChildren on the grid itself, not on your column definition:
groupSelectsChildren={true}
Demo.

MUIDataTable: In react application viewColumns options how to display the Checkbox List for column vertically

I have a MUI Table Implementation such that the options object viewColumns is set to true, which is supposed to display the popper to choose the columns to be displayed in vertical list of checkbox as shown below:
, but I am getting it horizontally as displayed in screenshot below:
The options to be passed in MUIDataTable components is defined as:
const options = {
filter: true,
filterType: "dropdown",
print: false,
viewColumns: true,
selectableRows: false,
onRowClick: (rowData) => {
console.log("RowClicked->", rowData);
},
responsive: "stacked",
fixedHeaderOptions: {
xAxis: false,
yAxis: true,
},
};
columns defines as:
export const DEAL_GRID_COLUMNS = [
{
name: "someReference",
label: "Some Reference",
options: {
filter: true,
sort: true,
},
},
{
name: "businessTeam",
label: "Business Teams",
options: {
filter: true,
sort: true,
},
},
{
name: "keyContact",
label: "Key Contact Lead",
options: {
filter: true,
sort: true,
},
},
.....
.....
.....
.....
];
and the component is consumed as
<MUIDataTable data={gridData} columns={DEAL_GRID_COLUMNS} options={options} />
here gridData is recieved from Api response
I made sample example using your options and I found viewColumns popper as vertical. I assume there is mui-datatable version issue. FYI, I am using "mui-datatables": "^2.14.0"
Here is the example:
import React, {useEffect, useState} from "react";
import MUIDataTable from "mui-datatables";
import axios from 'axios';
export default function DataTable() {
const [posts, setPost] = useState([]);
let signal = axios.CancelToken.source();
useEffect(() => {
let isSubscribed = true;
axios.get(`https://jsonplaceholder.typicode.com/posts`, {
cancelToken: signal.token,
})
.then(res => {
const posts = res.data;
setPost(posts);
}).catch(err => {
console.log(err);
});
return function cleanup() {
isSubscribed = false;
signal.cancel('Api is being canceled');
}
}, []);
const columns = ["id", "title", "body"];
const options = {
filter: true,
filterType: "dropdown",
print: false,
viewColumns: true,
selectableRows: 'none',
onRowClick: (rowData) => {
console.log("RowClicked->", rowData);
},
responsive: "stacked",
fixedHeaderOptions: {
xAxis: false,
yAxis: true,
},
};
return (
<MUIDataTable
title={"Posts"}
data={posts}
columns={columns}
options={options}
/>
);
}
You can check this output screen
I fixed this by overriding its maxWidth as
MuiPopover: {
paper: {
maxWidth: "16%",
},
}

Unable to convert timestamp to hours minutes and secondes in React apex-chart

I am using react apex chart to create a chart that will display the average response time for each agent.
I have managed to get the result in a timestamp format but i am unable to convert that into hours, minutes and seconds to display that in yaxis, i have checked the documentation docs link but they are giving examples for date time only.
here is the result that i am getting with the component bellow
import React, { useState } from 'react';
import Chart from 'react-apexcharts';
const AvgResponseTimeChart = (props) => {
const { prod_data } = props;
const [ data, setData ] = useState([
{
x: 'Agent one',
y: 1589670005
},
{
x: 'Agent one',
y: 1589670307
}
]);
const [ series, setSeries ] = useState([ { data } ]);
const [ options, setOptions ] = useState({
chart: {
type: 'bar',
height: 350
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '25%',
endingShape: 'rounded'
}
},
dataLabels: {
enabled: false
},
stroke: {
show: true,
width: 2,
colors: [ 'transparent' ]
},
xaxis: {
type: 'category'
},
yaxis: {
labels: {
datetimeFormatter: {
formatter: function(value, timestamp) {
return new Date(timestamp).toLocaleTimeString();
}
}
}
},
fill: {
opacity: 1
},
tooltip: {
y: {
formatter: function(value, timestamp) {
return new Date(timestamp);
}
}
}
});
return (
<div id="chart">
<Chart options={options} series={series} type="bar" height={350} />
</div>
);
};
export default AvgResponseTimeChart;
I have searched for similar issues without success if, someone can help me with that i will be really grateful
Try to add lables to yaxis in chartOptions this way:
labels: {
show: true,
formatter: (val) => { return new Date(val); }
}
And remove the tooltip as well.

Resources