react ag-Grid column show/hide

1、使用ag-Grid做数据表格非常方便,但是很多方法都是enterprise版本,即企业级付费才能使用的功能,例如Tool Panel,下面讲一下自定义Tool Panel来控制column的显示与隐藏功能

1.1、ag-Grid的tool panel具体效果图为

tool panel-摘自ag-Grid

我们自定义无非是创建一个div根据aggrid的表格数据生成一个树形结构,在用这个树形结构的按钮控制column的显示与隐藏,树形结构我们可以使用antd的tree,话不多说上代码

1.2、先使用ant的sider,创建一个customersider来包装tree

 this.updateColumns(newColumns, columnVisibleUpdate)} //回调方法,更新用户设置,返回一个新的columnDefs内包含hide属性的true or false
        /> 

2.1 customerSider.js

import React from 'react';
import { Layout, Tree, Input, Checkbox } from 'antd';
import './CustomSider.css';
import '../../Common/base.css';

const TreeNode = Tree.TreeNode;
const { Sider } = Layout;


export default class CustomSider extends React.Component {
  constructor(props) {
    super(props);
    this.defaultCheckedAllKeys = this.initAllCheckedArr();
    const { checkedKeyArr } = this.props;
    this.state = {
      expandedKeys: [],
      autoExpandParent: true,
      checkedKeys: checkedKeyArr,
      selectedKeys: [],
      defaultExpandAll: true,
      isSearched: false,
      indeterminate: true,
      checkAll: false,
      keys: checkedKeyArr,
    };
    this.dataList = [];
  }

  arrContentObject(arr, obj) {
    let contantObj = false;
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] == obj) {
        contantObj = true;
      }
    }
    return contantObj;
  }

  arrColumnIdContentObject(arr, obj) {
    let contantObj = false;
    for (let i = 0; i < arr.length; i++) {
      if (arr[i].columnId == obj) {
        contantObj = true;
      }
    }
    return contantObj;
  }

  getRootNodeKey(item, key) {
    const { columnDefs } = this.props;
    let tempItem = columnDefs[1];
    columnDefs.map((item) => {
      if (item.children) {
        if (this.arrColumnIdContentObject(item.children, key)) {
          tempItem = item;
        }
      }
    });
    return tempItem;
  }

  arrContentOtherAllArrObject(keyArr, otherArr) {
    let contantAll = true;
    for (let i = 0; i < otherArr.length; i++) {
      if (!this.arrContentObject(keyArr, otherArr[i].columnId)) {
        contantAll = false;
      }
    }
    return contantAll;
  }

  arrContentOtherArrObject(keyArr, otherArr) {
    let isContant = false;
    keyArr.map((item) => {
      for (let i = 0; i < otherArr.length; i++) {
        if (item == otherArr.columnId) {
          isContant = true;
          return isContant;
        }
      }
    });
    return isContant;
  }

  indexOfObjInArr(arr, obj) {
    let index = 0;
    for (let i = 0; i < arr.length; i++) {
      if (obj == arr[i]) {
        index = i;
        return index;
      }
    }
    return index;
  }

  componentDidMount() {
    this.generateList(this.props.columnDefs);
  }

  onExpand(expandedKeys) {
    this.setState({
      expandedKeys,
      autoExpandParent: false,
    });
  }

  getCheckedKeys() {
    const { downLoadColumnDefs } = this.props;
    const initCheckedks = [];
    downLoadColumnDefs.map((item) => {
      if (item.children) {
        for (let i = 0; i < item.children.length; i++) {
          if (!item.children[i].hide) {
            initCheckedks.push(item.children[i].columnId);
          }
        }
        if (this.arrleafAllShow(item.children)) {
          initCheckedks.push(item.columnId);
        }
      }
    });
    return initCheckedks;
  }


  handleCheckedKeysArr(e) {
    // const { columnDefs } = this.props;
    const { downLoadColumnDefs } = this.props;
    const { keys } = this.state;
    for (let i = 1; i < downLoadColumnDefs.length; i++) {
      if (downLoadColumnDefs[i].columnId == e.node.props.eventKey) {
        const item = downLoadColumnDefs[i];
        if (e.checked) {
          if (this.arrContentObject(keys, item.columnId)) {

          } else {
            keys.push(item.columnId);
          }
          for (let i = 0; i < item.children.length; i++) {
            if (this.arrContentObject(keys, item.children[i].columnId)) {

            } else {
              keys.push(item.children[i].columnId);
            }
          }
        } else {
          if (this.arrContentObject(keys, item.columnId)) {
            const itemIndex = this.indexOfObjInArr(keys, item.columnId);
            keys.splice(itemIndex, 1);
          }
          for (let i = 0; i < item.children.length; i++) {
            if (this.arrContentObject(keys, item.children[i].columnId)) {
              const itemIndex = this.indexOfObjInArr(keys, item.children[i].columnId);
              keys.splice(itemIndex, 1);
            }
          }
        }
      } else { // leaf
        const rootItem = this.getRootNodeKey(downLoadColumnDefs[i], e.node.props.eventKey);
        if (e.checked) { // checked = true
          if (this.arrContentObject(keys, e.node.props.eventKey)) {

          } else {
            keys.push(e.node.props.eventKey);
          }
          if (this.arrContentOtherAllArrObject(keys, rootItem.children)) { // all check
            if (this.arrContentObject(keys, rootItem.columnId)) { // contant root node

            } else {
              keys.push(rootItem.columnId);
            }
          }
        } else { // checked = fasle
          if (this.arrContentObject(keys, e.node.props.eventKey)) {
            const index = this.indexOfObjInArr(keys, e.node.props.eventKey);
            keys.splice(index, 1);
          }
          if (this.arrContentOtherArrObject(keys, rootItem.children)) {

          } else if (this.arrContentObject(keys, rootItem.columnId)) {
            const itemIndex = this.indexOfObjInArr(keys, rootItem.columnId);
            keys.splice(itemIndex, 1);
          }
        }
      }
    }
  }

  onCheck(checkedKeys, e) {
    const { downLoadColumnDefs } = this.props;
    this.handleCheckedKeysArr(e);
    const { keys } = this.state;
    this.setState({ checkedKeys: keys });
    const customerColumnDefs = this.matchColumnsKey(downLoadColumnDefs, e.node.props.eventKey, e.checked);
    this.handleFilterCheckState(keys.length);
    if (!this.state.checkAll && !this.state.indeterminate) {
      customerColumnDefs[0].hide = true;
    } else {
      customerColumnDefs[0].hide = false;
    }
    this.props.updateColumns(customerColumnDefs, true);
  }

  getParentKey(key, tree) {
    let parentKey;
    for (let i = 0; i < tree.length; i++) {
      const node = tree[i];

      if (node.children) {
        node.children.forEach((element) => {
          if (element.columnId === key) {
            element.showTreeNode = true;
          }
        });

        if (node.children.some(item => item.columnId === key)) {
          node.showTreeNode = true;
          parentKey = node.columnId;
        } else if (this.getParentKey(key, node.children)) {
          parentKey = this.getParentKey(key, node.children);
        }
        if (!!parentKey && node.columnId === key) {
          node.showTreeNode = true;
        }
      }
    }
    return parentKey || key;
  }

  matchColumnsKeyAll(downLoadColumnDefs, key, checked) {
    downLoadColumnDefs.map((item) => {
      if (item.children) {
        for (let i = 0; i < item.children.length; i++) {
          item.children[i].hide = !checked;
        }
      } else if (item.columnId === key) {
        item.hide = !checked;
      }
    });
    return [].concat(downLoadColumnDefs);
  }

  matchColumnsKey(downLoadColumnDefs, key, checked) {
    downLoadColumnDefs.map((item) => {
      if (item.children) {
        if (item.columnId == key) {
          for (let i = 0; i < item.children.length; i++) {
            item.children[i].hide = !checked;
          }
        } else {
          this.matchColumnsKey(item.children, key, checked);
        }
      } else if (item.columnId == key) {
        item.hide = !checked;
      }
    });
    return [].concat(downLoadColumnDefs);
  }

  generateList(data) {
    for (let i = 0; i < data.length; i++) {
      const node = data[i];
      this.dataList.push({ columnId: node.columnId, headerName: node.headerName });
      if (node.children) {
        this.generateList(node.children);
      }
    }
  }

  handleFilterCheckState(checkedLenth) {
    if (checkedLenth === this.defaultCheckedAllKeys.length) {
      this.state.checkAll = true;
      this.state.indeterminate = false;
    } else if (checkedLenth === 0) {
      this.state.checkAll = false;
      this.state.indeterminate = false;
    } else {
      this.state.checkAll = false;
      this.state.indeterminate = true;
    }
  }

  initAllCheckedArr() {
    const { columnDefs } = this.props;
    const initCheckedks = [];
    columnDefs.map((item) => {
      if (item.children) {
        initCheckedks.push(item.columnId);
        for (let i = 0; i < item.children.length; i++) {
          initCheckedks.push(item.children[i].columnId);
        }
      }
    });
    return initCheckedks;
  }

  searchTreeNodes(value) {
    const { columnDefs } = this.props;
    columnDefs.map((item) => {
      if (item.children) {
        item.showTreeNode = false;
        item.children.map((childrenItem) => {
          childrenItem.showTreeNode = false;
        });
      } else {
        item.showTreeNode = false;
      }
    });
    const expandedKeys = this.dataList.map((item) => {
      if (item.headerName && item.headerName.toLowerCase().indexOf(value.toLowerCase()) > -1) {
        return this.getParentKey(item.columnId, columnDefs);
      }
      return null;
    }).filter((item, i, self) => item && self.indexOf(item) === i);
    this.setState({
      expandedKeys,
      searchValue: value,
      autoExpandParent: true,
      isSearched: true,
    });
  }

  selectAllNodes(taget) {
    let tempCheckedIdArr = [];
    let newCol = [];
    const { downLoadColumnDefs } = this.props;
    if (taget.checked) { // all checked
      this.state.indeterminate = false;
      this.state.checkAll = true;
      tempCheckedIdArr = this.initAllCheckedArr();
      newCol = this.matchColumnsKeyAll(downLoadColumnDefs, 0, true);
    } else {
      this.state.checkAll = false;
      tempCheckedIdArr = [];
      newCol = this.matchColumnsKeyAll(downLoadColumnDefs, 0, false);
    }
    this.setState({ checkAll: this.state.checkAll, keys: tempCheckedIdArr, checkedKeys: tempCheckedIdArr });
    this.props.updateColumns(newCol, true);
  }

  renderTreeNodes(data, isSearched) {
    if (isSearched) {
      return data.map((item) => {
        if (item.headerName && item.showTreeNode) {
          if (item.children) {
            return (
              
                {this.renderTreeNodes(item.children, isSearched)}
              
            );
          }
          return ();
        }
        return ;
      });
    }
    return data.map((item) => {
      if (item.headerName) {
        if (item.children) {
          return (
            
              {this.renderTreeNodes(item.children, isSearched)}
            
          );
        }
        return ();
      }
      return ;
    });
  }

  render() {
    const { columnDefs } = this.props;
    const { isSearched } = this.state;
    const { checkedKeyArr } = this.props;
    this.handleFilterCheckState(checkedKeyArr.length);
    return (
      

Show/Hide Columns

{ this.selectAllNodes(e.target); } } /> this.searchTreeNodes(e.target.value)} />
this.onExpand(param)} expandedKeys={this.state.expandedKeys} autoExpandParent={this.state.autoExpandParent} onCheck={(param, e) => this.onCheck(param, e)} // checkedKeys={this.state.checkedKeys} checkedKeys={checkedKeyArr} // checkedKeys={this.state.defaultCheckedKey} keys={this.state.keys} onSelect={(selectParam) => { this.onSelect(selectParam); }} selectedKeys={this.state.selectedKeys} defaultExpandAll={this.state.defaultExpandAll} > {this.renderTreeNodes(columnDefs, isSearched)}
); } }

2.1.1 antd的tree给一个树形控件的数据源就可以自己管理checkedkeys,但是由于我们需要做搜索功能,如图,

完整数据源渲染的tree

搜索后的数据源渲染的tree

这里搜索的时候只能通过return ;那么return span的时候我们之前的checkedkeys,就会被改变而导致错误,所以我们只能自己维护checkedkeys,也就有了handleCheckedKeysArr方法,作为一个ios开发写前端确实有很多习惯上的不同,但是毕竟我以前了解过前端,虽然上述代码写的不是很好,但是功能没毛病,后期会在优化的,等着

3.1、以上为tool panel自定义,具体的隐藏和显示我们要从aggrid中寻找方法,有一个columnApi.setColumnVisible('filedId', true);,那么问题来了,如何触发这个方法呢,我们可以在aggrid中添加监听事件

onComponentStateChanged={(e) => {
            const { columnVisibleUpdate, downLoadColumnDefs } = this.props;
            if (columnVisibleUpdate) {
              this.handleColumnDefsVisibleChanged(downLoadColumnDefs);
            }
          }}

注意这个onComponentStateChanged这个方法会在很多时候调用,比如更新pin,sort等等,所以我们设置show or hide的时候要加个bool做判断,当aggrid的columnDefs发生改变的时候回调用此方法,然后我们根据用户设置的columnDefs来控制column显示和隐藏

handleColumnDefsVisibleChanged(columnDefs) {
    columnDefs.map((item) => {
      if (item.children) {
        for (let i = 0; i < item.children.length; i++) {
          this.columnApi.setColumnVisible(item.children[i].field, !item.children[i].hide);
        }
      } else {
        this.columnApi.setColumnVisible('lockPosition', !item.hide);
      }
    });
  }

lockPosition为我们的状态显示栏,当所有的column隐藏的时候,我们才隐藏lockPosition,至此,所有的column 显示和隐藏操作完成

你可能感兴趣的:(react ag-Grid column show/hide)