美文网首页
react ag-Grid column show/hide

react ag-Grid column show/hide

作者: fulen | 来源:发表于2018-11-19 10:21 被阅读184次

    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

    <CustomSider
              width={0}
              className="CustomSider"
              collapsed={collapsed} //外部开关,控制customerside的呼出与退出
              defaultCollapsed
              collapsedWidth={320}
              checkedKeyArr={initCheckedks} //初始化选中的节点
              columnDefs={this.state.columnDefs} //数据源即aggrid的数据源
              downLoadColumnDefs={defaultGridConfigure && defaultGridConfigure.layout && defaultGridConfigure.layout.customerColumnDefs && defaultGridConfigure.layout.customerColumnDefs.length ? defaultGridConfigure.layout.customerColumnDefs : this.state.columnDefs} //用作上传下载的数据源
              updateColumns={(newColumns, columnVisibleUpdate) => 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 (
                  <TreeNode title={item.headerName} key={item.columnId} dataRef={item}>
                    {this.renderTreeNodes(item.children, isSearched)}
                  </TreeNode>
                );
              }
              return (<TreeNode title={item.headerName} key={item.columnId} />);
            }
            return <span />;
          });
        }
        return data.map((item) => {
          if (item.headerName) {
            if (item.children) {
              return (
                <TreeNode title={item.headerName} key={item.columnId} dataRef={item}>
                  {this.renderTreeNodes(item.children, isSearched)}
                </TreeNode>
              );
            }
            return (<TreeNode title={item.headerName} key={item.columnId} />);
          }
          return <span />;
        });
      }
    
      render() {
        const { columnDefs } = this.props;
        const { isSearched } = this.state;
        const { checkedKeyArr } = this.props;
        this.handleFilterCheckState(checkedKeyArr.length);
        return (
          <div>
            <Layout>
              <Sider
                {...this.props}
              >
                <h3 className="siderTitle">Show/Hide Columns</h3>
                <div className="treeSearhWrap">
                  <Checkbox
                    className="selectAllNodes"
                    indeterminate={this.state.indeterminate}
                    checked={this.state.checkAll}
                    onChange={
                      (e) => {
                        this.selectAllNodes(e.target);
                      }
                    }
                  />
                  <Input
                    placeholder="Search..."
                    size="small"
                    className="searchNodes"
                    onChange={e => this.searchTreeNodes(e.target.value)}
                  />
                </div>
                <Tree
                  className="columnTree"
                  checkable
                  onExpand={param => 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)}
                </Tree>
              </Sider>
            </Layout>
          </div>
        );
      }
    }
    
    

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

    完整数据源渲染的tree 搜索后的数据源渲染的tree
    这里搜索的时候只能通过return <span />;那么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

          本文链接:https://www.haomeiwen.com/subject/bjlofqtx.html