Skip to content

docs(tree-checklist-example): root tree node correct selected state #13523

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

fabioloreggian
Copy link
Contributor

Fixed the checked state of the root node in the tree when the initial root state was checked, but then children were deselected, causing the root node to not update correctly.

Fixes #13314

Fixed the checked state of the root node in the tree when the initial root state was checked, but then children were deselected, causing the root node to not update correctly.

Fixes angular#13314
@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Oct 9, 2018
…ate when children updated

When all the children of a root node was selected the root node wasn't updated to selected correctly
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the this.checklistSelection is being repeated in this function a lot and it's somewhat long. Consider moving it into a constant like const selection = this.checklistSelection.

/** Whether all the descendants of the node are selected */
/**
* Whether all the descendants of the node are selected.
* And remove the node from this.checklistSelection if it isn't selected.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this function is the proper place to be doing the update. The function is used as a getter and it shouldn't be used to make changes to other properties. It might be more appropriate to do the change in the todoItemSelectionToggle method that is called when a checkbox is changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also thought about this; When toggling a child, it will need to find its parent and calculate its checked state. I'll refactor this after work today.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also when a child is toggled it calls the this.checklistSelection.toggle(node) directly, so I will have to make another function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to not be a function to get the parent of a node. So there are two options:

  1. Create a getParents function in FlatTreeControl
  2. Create a getParents function in tree-checklist-example.ts

For this PR I think changing only the tree-checklist-example.ts is the better way, then create a new Feature Request to implement getParents in FlatTreeControl

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been looking at this the whole day and thinking about a solution.

Firstly the problem lies in the fact that the isSelected state of parent nodes aren't the same value if you select it or select all the children.

So my solution was to try and rectify this, and keep the parent nodes selected state consistent.

I agree with your statement above stating that descendantsAllSelected is a getter and should be a pure function and not mutate the state of the object, but because of the nature of nested (even flattened) structures it can potentially be a very expensive operation to update every parent up the tree structure (recursive), which what needs to happen if we are going to change the state of the parent nodes on the (change) function.

So I propose my solution which tries to be a lightweight as possible (no recursion), but it does unfortunately mutate state in the getter. I have moved the mutating function to a new function.

Your thoughts would be greatly appreciated

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that recursing through the entire tree would be that expensive since it only happens once when the checkbox is toggled. Even if it's thousands of nodes, we're probably looking at something that's going to take a couple of milliseconds max. If we put aside the fact that the getter shouldn't be changing any state, there's still the issue that the getter is invoked for every change detection cycle, even if the user didn't interact with the tree.

);
if (this.checklistSelection.isSelected(node) && !descAllSelected) {
this.checklistSelection.deselect(node);
} else if(!this.checklistSelection.isSelected(node) && descAllSelected) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a space after the else if.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ill refactor this when I do the above changes

Root node correctly changes selected state based on children changing selected state
@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and have the pull request author add another comment and the bot will run again. If the bot doesn't comment, it means it doesn't think anything has changed.

@googlebot googlebot added cla: no PR author must sign Google's Contributor License Agreement: https://opensource.google.com/docs/cla and removed cla: yes PR author has agreed to Google's Contributor License Agreement labels Oct 10, 2018
@crisbeto
Copy link
Member

@fabioloreggian looks like you pushed a commit signed with a different email addressed which causes the CLA check to fail.

@fabioloreggian
Copy link
Contributor Author

@fabioloreggian looks like you pushed a commit signed with a different email addressed which causes the CLA check to fail.

I saw, and I am not sure why it did that. I'm trying to rectify it now.

Removed the parent selection logic from the getter to its own function.
@googlebot
Copy link

CLAs look good, thanks!

@googlebot googlebot added cla: yes PR author has agreed to Google's Contributor License Agreement and removed cla: no PR author must sign Google's Contributor License Agreement: https://opensource.google.com/docs/cla labels Oct 15, 2018
Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

descendantsAllSelected(node: TodoItemFlatNode): boolean {
const descendants = this.treeControl.getDescendants(node);
return descendants.every(child => this.checklistSelection.isSelected(child));
const descAllSelected = descendants.every(child =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can just use return descendants.every(...) here instead of assigning it to a constant.

@crisbeto crisbeto added pr: lgtm action: merge The PR is ready for merge by the caretaker target: patch This PR is targeted for the next patch release labels Oct 16, 2018
@josephperrott josephperrott merged commit f456e85 into angular:master Oct 17, 2018
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Select-all toggle in tree example has the wrong state
4 participants