N00ts / vue3-treeview

a simple treeview in vue js 3
MIT License
71 stars 61 forks source link

how to make parent node checked if all child nodes checked #42

Closed swuqi closed 5 months ago

swuqi commented 8 months ago

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

sorexalpinus commented 8 months ago

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 8 months ago

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 :)

N00ts commented 5 months ago

closed