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. */