是否有一种为List实现列选择器的简单方法?

时间:2017-10-06 13:20:00

标签: admin-on-rest

我们将实现一个columnpicker,目前我唯一的想法就是实现一个包装List的ColumnPickableList。这还将包含一个复选框列表,使用户可以隐藏列。

但在我开始之前,我只是想知道我是否重新启动了车轮,是否有更简单的方法来解决这个问题?

2 个答案:

答案 0 :(得分:2)

没有简单的方法。您必须为该

实现自己的List组件

答案 1 :(得分:0)

我正在跟进,因为我正在努力使这项工作。也许是因为我选择创建一个过滤器来过滤要显示的子项。所以从技术上来说,这种方法并没有实现自己的List。

我做了一个天真的草稿,我希望它可以工作,但它无法重新渲染孩子,即使他们在父组件中被更改/过滤。

ColumnPickableList中的console.log(..)render() - 函数确实打印了正确的子/道具,但是孩子们仍然不会更新/重新渲染。任何线索为什么?这种做法太天真了吗?

以下是目前的草案:

<强> ColumnPicker.js

import React, { PropTypes } from 'react';

import Checkbox from 'material-ui/Checkbox';

export default class ColumnPicker extends React.Component {

  constructor(props) {
    super(props);
    this.onCheck = this.onCheck.bind(this);
  }

  onCheck(column, isChecked) {
    return this.props.onCheckboxChanged(column, isChecked);
  }

  renderCheckbox(column, onCheck) {
    const disabled = (column.source === 'id');
    return (<Checkbox key={column.source} label={column.source.toUpperCase()} onCheck={(event, checked) => onCheck(column, checked)} defaultChecked disabled={disabled} />);
  }

  render() {
    const columns = this.props.columns || [];

    return (
      <div className="column-picker">
        {columns.map((column) => {
          return this.renderCheckbox(column, this.onCheck);
        })}
      </div>
    );
  }
}

ColumnPicker.propTypes = {
  columns: PropTypes.array,
  onCheckboxChanged: PropTypes.func,
};

ColumnPicker.defaultProps = {
  columns: [], // [{source: myField, checked: true} ...]
};

<强> ColumnPickableList.js:

import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { List, Datagrid } from 'admin-on-rest';
import ColumnPicker from './ColumnPicker';

import { toggleColumnPickerStatusAction, initializeColumnPickerAction } from './actions';

export class ColumnPickableList extends React.Component {

  componentWillMount() {
    let columnSourceNames = [];
    if (this.props.children) {
      columnSourceNames = React.Children.map(this.props.children, (child) => {
        return ({ source: child.props.source, checked: true });
      });
    }
    const columnsDisplayed = columnSourceNames.filter((column) => column.source);
    this.props.initializeColumnPicker(this.props.resource, columnsDisplayed);
  }

  shouldComponentUpdate(nextProps) {
    const diff = nextProps.columnsDisplayed.filter((currentColumn) => {
      return !this.props.columnsDisplayed.some((prevColumn) => {
        return currentColumn.source === prevColumn.source && currentColumn.checked === prevColumn.checked;
      });
    });

    return diff.length > 0;
  }

  removeHiddenColumns(children) {
    return React.Children.map(children, (child) => {
      if (!child.props.source) {
        return child;
      }
      const column = this.props.columnsDisplayed.find((columnDisplayed) => {
        return columnDisplayed.source === child.props.source;
      });

      if (this.props.columnsDisplayed.length === 0 || (column && column.checked)) {
        return React.cloneElement(child);
      }
      return null;
    });
  }

  render() {
    const { children, ...rest } = this.props;
    const displayedChildren = this.removeHiddenColumns(children);
    console.log('Does it render? Rendering children', displayedChildren.map((child) => child.props.source));

    return (
      <div className="columnpickable-list">
        <ColumnPicker columns={this.props.columnsDisplayed} onCheckboxChanged={this.props.handleCheckboxChanged} />
        <List {...rest}>
          <Datagrid>
            {displayedChildren}
          </Datagrid>
        </List>
      </div>
    );
  }
}

ColumnPickableList.propTypes = {
  resource: PropTypes.string,
  columnsDisplayed: PropTypes.array,
  children: PropTypes.node,
  initializeColumnPicker: PropTypes.func,
  handleCheckboxChanged: PropTypes.func,
};

ColumnPickableList.defaultProps = {
  columnsDisplayed: [],
};


function mapStateToProps(state) {
  return {
    columnsDisplayed: state.columnsDisplayed || [],
  };
}

<强> actions.js:

export const actions = {
  INIT_COLUMNPICKER: 'INIT_COLUMNPICKER',
  TOGGLE_COLUMNPICKER_STATUS: 'UPDATE_COLUMNPICKER_STATUS',
  UPDATE_COLUMNPICKER_STATUSES: 'UPDATE_COLUMNPICKER_STATUSES',
}


export function initializeColumnPickerAction(resource, columns) {
  return {
    type: actions.INIT_COLUMNPICKER,
    columns,
    meta: { resource },
  };
}


export function toggleColumnPickerStatusAction(column) {
  return {
    type: actions.TOGGLE_COLUMNPICKER_STATUS,
    column,
  };
}

<强> reducers.js:

import { actions } from './actions';

function columnPickerReducer(state = [], action) {
  switch (action.type) {
    case actions.INIT_COLUMNPICKER: {
      console.log('Init columnopicker reducer');
      return action.columns;
    }
    case actions.TOGGLE_COLUMNPICKER_STATUS: {
      const columns = state.map((column) => {
        if (column.source === action.column.source) {
          return { ...column, checked: !column.checked };
        }
        return column;
      });
      return columns;
    }
    default:
      return state;
  }
}

export default columnPickerReducer;

父组件的示例摘录:

...

<ColumnPickableList title="SillyStuff" {...props}>
  <TextField source="id" />
  <TextField source="NAME" />
  <TextField source="SILLY_NAME" />
  <TextField source="CHANGED_BY" />
  <DateField source="CHANGED_TS" showTime />
  <EditButton />
  <DeleteButton />
</ColumnPickableList>
...