Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I specify a minimum width for a column using react-resizable and antd's table?

Tags:

reactjs

antd

I'm trying to make antd's table have resizable columns. It works good. But I can't make any column smaller than its inner text, when I'm resizing the column. I've tried to set a minimal width, but it doesn't work. At least in my case. I believe there should be some properties, that I can pass to resizable component in order to set a minimal width. I've found the example How antd table can work together with react-resizable library. Right here https://ant.design/components/table/ But even in this example it works the same as in my case.

import React, { useState } from "react";
import { Button, Icon } from "antd";
import { Resizable } from "react-resizable";
import moment from "moment";
import UniqIdsGenerator from "lib/uniqIdsGenerator";
import SearchData from "containers/SearchData";
import { StyledTable, LikeLink, Header, SearchWrapper } from "./style";

const ResizeableTitle = props => {
    const { onResize, width, onClick, ...restProps } = props;

    const [allowClick, setAllowClick] = useState(true);

    if (!width) {
        return <th {...restProps} />;
    }

    return (
        <Resizable
            width={width}
            height={0}
            onResize={onResize}
            onMouseDown={e => {
                setAllowClick(true);
            }}
            onResizeStart={e => {
                setAllowClick(false);
            }}
            onClick={e => {
                if (allowClick && typeof onClick === "function") {
                    onClick(e);
                }
            }}
        >
            <th {...restProps} />
        </Resizable>
    );
};

const RowActions = ({ actions, uniqId, onRowAction, record, user }) =>
    actions.map(({ label, action }, fieldName) => {
        let { status } = record;
        return label === "log" && !statuses[status] ? null : (
            <LikeLink
                key={fieldName}
                id={uniqId.getTableRowAction(action)}
                onClick={e => {
                    e.preventDefault();
                    onRowAction({ record, action });
                }}
            >
                {label}
            </LikeLink>
        );
    });

const HeaderActions = ({ actions, handleClick, uniqId, isAllowed }) =>
    actions.map(({ label, action, icon }, fieldName) => {
        let button;
        label == "Add Upload" && !isAllowed
            ? (button = (
                  <Button
                      key={fieldName}
                      id={uniqId.getHeaderButton(fieldName)}
                      onClick={() => handleClick(action)}
                      disabled={true}
                      id={"disabledButton"}
                  >
                      {icon && <Icon type={icon} />}
                      {label}
                  </Button>
              ))
            : (button = (
                  <Button
                      key={fieldName}
                      id={uniqId.getHeaderButton(fieldName)}
                      onClick={() => handleClick(action)}
                  >
                      {icon && <Icon type={icon} />}
                      {label}
                  </Button>
              ));

        return button;
    });

class DataTable extends React.PureComponent {
    state = {
        columns: []
    };

    components = {
        header: {
            cell: ResizeableTitle
        }
    };

    uniqId = new UniqIdsGenerator(this.props.prefixId);

    componentDidMount() {
        const { handleClickOnTableRowAction } = this.props;
        this.getColumns({
            onRowAction: data => handleClickOnTableRowAction(data)
        });
    }

    handleResize = index => (e, { size }) => {
        this.setState(({ columns }) => {
            const nextColumns = [...columns];
            nextColumns[index] = {
                ...nextColumns[index],
                width: size.width
            };
            // console.log(size.width)
            return { columns: nextColumns };
        });
    };

    getColumns = ({ onRowAction }) => {
        const { columnsSchema, user } = this.props;
        const { uniqId } = this;

        let totalColumnsWidth = 250;

        const getTotalColumnWidth = column => {
            if (column.width) {
                totalColumnsWidth += column.width;
            }
        };

        const checkForWidth = column =>
            ((column.width && totalColumnsWidth) || column.isWidthFixed) &&
            column.width;

        const prepareToTable = (column, fieldName) => {
            return {
                title: column.label,
                dataIndex: column.fieldName,

                orgIndex: (text, record) => column.fieldName,
                key: column.key ? column.key : column.fieldName,
                width: checkForWidth(column),
                defaultSortOrder: column.defaultSortOrder,
                sorter: column.sortAs
                    ? (a, b) => sortAs[column.sortAs](a, b, column.fieldName)
                    : "",
                // filters: column.filters && column.filters,
                onFilter: (value, record) => record.traceType.match(value),
                // onHeaderCell: () => ({ 'id': uniqId.getTableTheadTh(fieldName) }),
                render: (text, record) => {
                    return {
                        props: {
                            id: uniqId.getTableTbodyTd(fieldName),
                            className: "classNameOfCell"
                        },
                        children: addChildren(column, record)
                    };
                }
            };
        };

        const addChildren = (column, record) => {
            if (column.render) {
                return column.render(record);
            } else if (column.actions) {
                return (
                    <RowActions
                        {...column}
                        user={user}
                        uniqId={this.uniqId}
                        onRowAction={onRowAction}
                        record={record}
                    />
                );
            }
            // }
            else {
                return record[column.fieldName];
            }
        };

        columnsSchema && columnsSchema.forEach(getTotalColumnWidth);

        const cols = columnsSchema.map(prepareToTable);

        // columnsSchema && columnsSchema.forEach(getTotalColumnWidth);

        const columns =
            cols &&
            cols.map((col, index) => ({
                ...col,
                onHeaderCell: column => ({
                    width: column.width,
                    onResize: this.handleResize(index)
                })
            }));

        columns && this.setState({ columns: columns });
    };

    render() {
        const {
            data,
            staticData,
            getRowKey,
            onSearch,
            loading,
            handleClickOnTableRowAction,
            handleClickOnHeaderButton,
            headerActionsSchema,
            isSearchDisabled,
            isAllowed
        } = this.props;

        const { uniqId } = this;
        const { columns } = this.state;

        return (
            <div id={uniqId.getComponentDivWrapper()}>
                <Header id={uniqId.getHeaderDiv()}>
                    {!isSearchDisabled && (
                        <SearchWrapper>
                            <SearchData
                                id={uniqId.getHeaderInput()}
                                placeholder="Search"
                                onSearch={e => onSearch(e, staticData)}
                            />
                        </SearchWrapper>
                    )}
                    <HeaderActions
                        actions={headerActionsSchema ? headerActionsSchema : []}
                        uniqId={uniqId}
                        handleClick={handleClickOnHeaderButton}
                        isAllowed={isAllowed}
                    />
                </Header>
                <div id={uniqId.getTableDivWrapper()}>
                    <StyledTable
                        loading={loading}
                        dataSource={data}
                        bordered
                        rowKey={getRowKey}
                        size="small"
                        pagination={{ pageSize: 10 }}
                        onRow={(row, fieldName) => ({
                            id: uniqId.getTableTbodyTr(fieldName)
                        })}
                        onHeaderRow={(row, fieldName) => ({
                            id: uniqId.getTableTheadTr(fieldName)
                        })}
                        components={this.components}
                        columns={columns}
                    />
                </div>
            </div>
        );
    }
}

export default DataTable;
like image 733
foxer bixer Avatar asked Sep 06 '19 12:09

foxer bixer


1 Answers

To specify the minimum width of a column:

  1. we need to add to the column object(s) a new property of minWidth
columns: [
      {
        title: 'Date',
        dataIndex: 'date',
        width: 200,
        minWidth: 120
      },
]
  1. we pass down the column prop:
const columns = this.state.columns.map((col, index) => ({
      ...col,
      onHeaderCell: column => ({
        minWidth: column.minWidth,
        width: column.width,
        onResize: this.handleResize(index)
      })
    }));
  1. we add the prop: minConstraints={[minWidth, 0]} to <Resizable /> wrapper

NOTE: The same will work for max width but we pass the maxWidth prop to maxConstraints={[maxWidth, 0]}. Also about the property names we could use whatever name we want for minWidth or maxWidth. They are just variables that pass down the numbers we want.

Example on codesandbox: https://codesandbox.io/s/minwidthresizable-cp25n

The example was based on the official demo: https://ant.design/components/table/#components-table-demo-resizable-column

like image 98
AndreasT Avatar answered Oct 08 '22 00:10

AndreasT