美文网首页
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

    1、使用ag-Grid做数据表格非常方便,但是很多方法都是enterprise版本,即企业级付费才能使用的功能,例...

  • jQuery——动画

    show() and hide() 1. show()和hide() show()方法和hide()方法是jQue...

  • JQ笔记——jquery效果

    hide()/show() hide(speed,callback); show(speed,callback);...

  • jQuery效果

    jQuery hide() 和 show() 通过 jQuery,您可以使用 hide() 和 show() 方法...

  • jQuery效果

    jQuery hide() 和 show() 通过 jQuery,您可以使用 hide() 和 show() 方法...

  • jQuery效果笔记

    显示和隐藏show与hide $("#hide").cilck(function(){ $("p").hide...

  • jQuery|隐藏和显示

    方式一:使用 hide() 和 show() 方法 通过 jQuery,您可以使用 hide() 和 show()...

  • jQuery的动画

    显示和隐藏元素 1,无过渡(show,hide,toggle) 2,有过渡(show,hide,toggle) 3...

  • 第 7 章 jQuery 动画特效

    调用 show() 和 hide() 方法显示和隐藏元素 show()和hide()方法用于显示或隐藏页面中的元素...

  • jQuery动画

    2019-06-05 show与hide方法 显示:show(执行速度,[回调函数]); 隐藏:hide(执行速度...

网友评论

      本文标题:react ag-Grid column show/hide

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