N00ts/vue3-treeview

how to make parent node checked if all child nodes checked

swuqi opened this issue · 3 comments

swuqi commented

Is there an option to make a parent node checked if all child nodes checked?

Looks like cascade check/uncheck functionality is not covered yet ...

You can use the following:

<div v-if="loaded">
  <tree
      :nodes="nodes"
      :config="config"
      @node-checked="onNodeStateChange"
      @node-unchecked="onNodeStateChange"
  ></tree>
</div>
</template>

<script>
import Tree from "vue3-treeview";
import "vue3-treeview/dist/style.css";

export default {
  name: "Test",
  components: {Tree},
  created() {
    for(const nId in this.nodes) this.nodes[nId].id = nId;
    this.loaded = true;
  },
  methods: {
    onNodeStateChange(node) {
      this.cascadeCheck(node);
    },
    cascadeCheck(node) {
      node.state.indeterminate = false;
      this.updateChildNodes(node);
      this.updateParentNodes(node);
    },
    updateChildNodes(node) {
      if(node.children?.length) {
        node.children.forEach(chNodeId => {
          if(!this.nodes[chNodeId].state) this.nodes[chNodeId].state = {};
          this.nodes[chNodeId].state.checked = node.state.checked;
          this.updateChildNodes(this.nodes[chNodeId]);
        });
      }
    },
    updateParentNodes(node)
    {
      let parents = [];
      while (node) {
        let parent = this.findParent(node);
        if(parent) parents.push(parent);
        node = parent;
      }
      parents.forEach(pNode => {
        let checked = 0;
        let total = pNode.children.length;
        pNode.children.forEach(ch => {
          if(this.nodes[ch].state.checked) checked++;
        });
        if(checked === total) {
          pNode.state.indeterminate = false;
          pNode.state.checked = true;
        }
        else if(checked === 0) {
          pNode.state.indeterminate = false;
          pNode.state.checked = false;
        }
        else {
          pNode.state.indeterminate = true;
          pNode.state.checked = false;
        }
      });
    },
    findParent(node) {
      for(const nId in this.nodes) {
        let cNode = this.nodes[nId];
        if (cNode.children) {
          if(cNode.children.includes(node.id)) return cNode;
        }
      }
      return null;
    }
  },
  data() {
    return {
      loaded: false,
      config: {
        roots: ["id1", "id2"],
        checkboxes: true,
        checkMode: 'auto'
      },
      nodes: {
        id1: {
          text: "text1",
          children: ["id11", "id12"],
        },
        id11: {
          text: "text11",
          children: ["id111","id112"]
        },
        id111: {
          text: "text 1.1.1"
        },
        id112: {
          text: "text 1.1.2"
        },
        id12: {
          text: "text12",
        },
        id2: {
          text: "text2",
        },
      },
    };
  },
}
</script>`
N00ts commented

You are completely right. Cascading is only handeled for normal purpose which is
Parent node is checked only if all his child are checked.
If you need another behavior, you can still use the "manual" check mode :)

closed