I am trying to add a column to the react table using an add column button, but I am a little confused on how to implement this. I want to be able to add a column to the corresponding side that the button is clicked. Do I need to create a custom function and add it to my columns array or is there an easier way to implement this?
Here is the code.
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable guard-for-in */
/* eslint-disable no-restricted-syntax */
/* eslint-disable react/jsx-props-no-spreading */
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { useTable } from 'react-table';
import data from '../Data/data.json';
import './Table.css';
const Styles = styled.div`
table {
border-spacing: 0;
border: 1px solid black;
width: 970px;
tr {
:last-child {
td {
border-bottom: 0;
height: 500px;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`;
const HarveyBall = (initialValue) => {
const [value, setValue] = useState(initialValue);
const onClick = () => {
if(value === 'Empty'){
setValue('Quarter');
}
if(value === 'Quarter'){
setValue('Half');
}
if(value === 'Half'){
setValue('Three-Quarter');
}
if(value === 'Three-Quarter'){
setValue('Full');
}
if(value === 'Full'){
setValue('Empty');
}
};
if(value === "Empty"){
return (
<div type="button" label="Empty" className="harvey none" onClick={onClick} />
);
}
if(value === "Quarter"){
return (
<div type="button" label="Quarter" className="harvey quarters quarter" onClick={onClick} />
);
}
if(value === "Half"){
return (
<div type="button" label="Half" className="harvey quarters half" onClick={onClick} />
);
}
if(value === "Three-Quarter"){
return (
<div type="button" label="Three-Quarter" className="harvey quarters three-quarters" onClick={onClick} />
);
}
if(value === "Full"){
return (
<div type="button" label="Full" className="harvey quarters full" onClick={onClick} />
);
}
return null;
};
const defaultPropGetter = () => ({});
const EditableCell = ({
value: initialValue,
row: { index },
column: { id },
updateMyData,
}) => {
const [value, setValue] = React.useState(initialValue);
const onChange = e => {
setValue(e.target.value);
};
const onBlur = () => {
updateMyData(index, id, value);
};
React.useEffect(() => {
setValue(initialValue);
}, [initialValue]);
return id === "strategicInitiative" || index === 5 ? <textarea value={value} onChange={onChange} onBlur={onBlur} style={{ width: '100%', focus: 'none', outline: 'none', border: 'none',resize: 'none', expand: {height: '1em', width: '50%', padding: '3px'}}}/> : HarveyBall(initialValue);
};
const defaultColumn = {
Cell: EditableCell,
};
function Table({ columns, getHeaderProps = defaultPropGetter, updateMyData, }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({
columns,
data,
updateMyData,
defaultColumn,
});
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => column.hideHeader === false ? null : (
<th
{...column.getHeaderProps([
{
className: column.className,
style: column.style,
},
getHeaderProps(column),
])}
>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>;
})}
</tr>
);
})}
</tbody>
</table>
);
}
export default function MatrixTable() {
const addTasks = () => {
const taskLength = [];
for(let i = 0; i < data.length; i += 1){
for(const [key] of Object.entries(data[i])){
if(key.includes("T")){
taskLength.push(key[1]);
}
}
}
const newTaskLength = (parseInt(taskLength[taskLength.length - 1], 10) + 1) ;
for(let i = 0; i < data.length; i += 1){
data[i][`T${newTaskLength}`] = "";
}
};
const taskButton = () => (
<>
<div>Tasks</div>
<button onClick={addColumns} type='button'>Add Column</button>
</>
);
const goalButton = () => (
<>
<div>Goals</div>
<button type='button'>Add Column</button>
</>
);
const columns = React.useMemo(
() => [
{
Header: () => taskButton(),
accessor: 'tasks',
style: {
width: '255px',
height: '49px',
background: '#fdf5ed',
fontSize: '16px',
color: '#f2994a',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'T1'
},
{
hideHeader: false,
accessor: 'T2'
},
{
hideHeader: false,
accessor: 'T3'
},
{
hideHeader: false,
accessor: 'T4'
},
{
hideHeader: false,
accessor: 'T5'
},
]
},
{
Header: "Strategic Inititiatives",
accessor: "strategicInitiative ",
style: {
color: '#323b3e',
width: '460px',
height: '49px',
background: '#f2f2f2',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'strategicInitiative'
}
]
},
{
Header: goalButton(),
accessor: 'goals',
style: {
color: '#56ccf2',
width: '255px',
height: '49px',
background: '#f8fcfe',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'G1'
},
{
hideHeader: false,
accessor: 'G2'
},
{
hideHeader: false,
accessor: 'G3'
},
{
hideHeader: false,
accessor: 'G4'
},
{
hideHeader: false,
accessor: 'G5'
}
]
},
],
[]
);
const addColumns = () => {
for(let i = 0; i < columns.length; i += 1) {
if(columns[i].accessor === "tasks"){
console.log(columns[i]);
columns[i].columns.push({
hideHeader: false,
accessor: 'T6'
});
}
}
};
addColumns();
const [, setData] = useState(data);
useEffect(() => {
setData(data);
}, [data]);
const updateMyData = (rowIndex, columnId, value) => {
setData(old =>
old.map((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex],
[columnId]: value,
};
}
return row;
})
);
};
return (
<Styles>
<Table columns={columns} data={data} updateMyData={updateMyData}/>
</Styles>
);
}
Yeah, changing
columns
array(not by mutation, but by settingcolumns
prop to new required array) is the best way to go.