diff --git a/src/material-examples/tree-checklist/tree-checklist-example.html b/src/material-examples/tree-checklist/tree-checklist-example.html index a92475a65a59..5fc96882e1fa 100644 --- a/src/material-examples/tree-checklist/tree-checklist-example.html +++ b/src/material-examples/tree-checklist/tree-checklist-example.html @@ -3,7 +3,7 @@ {{node.item}} + (change)="todoLeafItemSelectionToggle(node)">{{node.item}} diff --git a/src/material-examples/tree-checklist/tree-checklist-example.ts b/src/material-examples/tree-checklist/tree-checklist-example.ts index 8d91541e9add..b3c1461cc4b6 100644 --- a/src/material-examples/tree-checklist/tree-checklist-example.ts +++ b/src/material-examples/tree-checklist/tree-checklist-example.ts @@ -168,10 +168,13 @@ export class TreeChecklistExample { return flatNode; } - /** Whether all the descendants of the node are selected */ + /** Whether all the descendants of the node are selected. */ descendantsAllSelected(node: TodoItemFlatNode): boolean { const descendants = this.treeControl.getDescendants(node); - return descendants.every(child => this.checklistSelection.isSelected(child)); + const descAllSelected = descendants.every(child => + this.checklistSelection.isSelected(child) + ); + return descAllSelected; } /** Whether part of the descendants are selected */ @@ -188,6 +191,61 @@ export class TreeChecklistExample { this.checklistSelection.isSelected(node) ? this.checklistSelection.select(...descendants) : this.checklistSelection.deselect(...descendants); + + // Force update for the parent + descendants.every(child => + this.checklistSelection.isSelected(child) + ); + this.checkAllParentsSelection(node); + } + + /** Toggle a leaf to-do item selection. Check all the parents to see if they changed */ + todoLeafItemSelectionToggle(node: TodoItemFlatNode): void { + this.checklistSelection.toggle(node); + this.checkAllParentsSelection(node); + } + + /* Checks all the parents when a leaf node is selected/unselected */ + checkAllParentsSelection(node: TodoItemFlatNode): void { + let parent: TodoItemFlatNode | null = this.getParentNode(node); + while (parent) { + this.checkRootNodeSelection(parent); + parent = this.getParentNode(parent); + } + } + + /** Check root node checked state and change it accordingly */ + checkRootNodeSelection(node: TodoItemFlatNode): void { + const nodeSelected = this.checklistSelection.isSelected(node); + const descendants = this.treeControl.getDescendants(node); + const descAllSelected = descendants.every(child => + this.checklistSelection.isSelected(child) + ); + if (nodeSelected && !descAllSelected) { + this.checklistSelection.deselect(node); + } else if (!nodeSelected && descAllSelected) { + this.checklistSelection.select(node); + } + } + + /* Get the parent node of a node */ + getParentNode(node: TodoItemFlatNode): TodoItemFlatNode | null { + const currentLevel = this.getLevel(node); + + if (currentLevel < 1) { + return null; + } + + const startIndex = this.treeControl.dataNodes.indexOf(node) - 1; + + for (let i = startIndex; i >= 0; i--) { + const currentNode = this.treeControl.dataNodes[i]; + + if (this.getLevel(currentNode) < currentLevel) { + return currentNode; + } + } + return null; } /** Select the category so we can insert the new item. */