Skip to content
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

Not able to select/deselect checkbox in spfx-controls-react TreeView after assign the defaultSelectedKeys value #870

Closed
sumitdeyonline opened this issue Apr 7, 2021 · 30 comments
Labels
status:fixed-next-drop Issue will be fixed in upcoming release.
Milestone

Comments

@sumitdeyonline
Copy link

Not able to select/deselect the checkboxes in spfx-controls-react multi-select TreeView after assign the defaultSelectedKeys value, it selected the default selected keys(node) while loading the webpart though. After loading we are not able to select/deselect any checkboxes.

          <TreeView
            items={this.testdata}
            defaultExpanded={false}
            selectionMode={TreeViewSelectionMode.Multiple}
            selectChildrenIfParentSelected={true}
            showCheckboxes={true}
            treeItemActionsDisplayMode={TreeItemActionsDisplayMode.ContextualMenu}
            defaultSelectedKeys={['5678','1234']}
            expandToSelected={true}
            defaultExpandedChildren={false}
            onExpandCollapse={this.onExpandCollapseTree}
            onSelect={this.onItemSelected}
            onRenderItem={this.renderCustomTreeItem} 
          />

When I commented out the defaultSelectedKeys values, everything else is working perfectly.

@ghost
Copy link

ghost commented Apr 7, 2021

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

@ghost ghost added the Needs: Triage 🔍 label Apr 7, 2021
@joelfmrodrigues
Copy link
Collaborator

Hi @sumitdeyonline, I was unable to recreate this issue.
Could you please share the package version that you are using, and also test with the latest one if not already used (if possible).

@sumitdeyonline
Copy link
Author

Thank you, Joel for your response. Please find the package I have used in my project.

I had the same issue with @pnp/spfx-controls-react 2.5 and 2.6 as well. Currently using the latest version(3.0.0).

"dependencies": {
"@microsoft/sp-core-library": "1.11.0",
"@microsoft/sp-lodash-subset": "1.11.0",
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
"@microsoft/sp-property-pane": "1.11.0",
"@microsoft/sp-webpart-base": "1.11.0",
"@pnp/spfx-controls-react": "^3.0.0",
"@types/es6-promise": "0.0.33",
"@types/react": "16.8.8",
"@types/react-dom": "16.8.3",
"@types/webpack-env": "1.13.1",
"office-ui-fabric-react": "6.214.0",
"react": "16.8.5",
"react-dom": "16.8.5"
},

@YannickRe
Copy link
Contributor

@sumitdeyonline @joelfmrodrigues I have fixed this behavior in my PR that is currently open to be reviewed/merged => #864
The behavior manifests itself only when trying to deselect children.

Reason: when having selectChildrenIfParentSelected to true, it will always select the children on select, unselect, mount and update. You have a callback function on item select which, I assume, triggers a rerender of the parent and thus of the treeView control. As a result, the Treeview control will take your default keys and select their children again (even if you just clicked deselect).

My fixes:

  • Introduce a more granular setting so you can decide when it has to do the children selection: only on mount, on select, on deselect, on update, OR any combination of those 4. In my case, I want this to happen on select and deselect only. On mount and update, I want it to just select the keys I provide.
  • I fixed a second issue with the defaultSelectedKeys, where it would never select children even if you provided their key in defaultSelectedKeys

@joelfmrodrigues
Copy link
Collaborator

@YannickRe many thanks for the update, that's great!
Will review the PR as soon as possible

@YannickRe
Copy link
Contributor

You are welcome!

I chose the flagged enum for backwards compatibility, so you can still have to "all on" or "all off" functionality like you currently have. In my opinion, you should not do the child selection on update, and probably not on mount either but to not break anyone I chose the flagged enum direction.

@sumitdeyonline
Copy link
Author

Please let me know when it would be released

@YannickRe
Copy link
Contributor

Like you, I hope soon. I have a project waiting for this 😃

@AJIXuMuK
Copy link
Collaborator

The PR with the fix has been merged and is available in v2-beta

@AJIXuMuK AJIXuMuK added status:fixed-next-drop Issue will be fixed in upcoming release. and removed Needs: Attention 👋 labels Apr 11, 2021
@AJIXuMuK AJIXuMuK added this to the 2.7.0 milestone Apr 11, 2021
@sumitdeyonline
Copy link
Author

When it would be available for us to use.

@AJIXuMuK
Copy link
Collaborator

@sumitdeyonline - you can already test it using the v2 beta version

@sumitdeyonline
Copy link
Author

Thank you @AJIXuMuK.

@YannickRe , Still I am not able to select/deselect after setting the value of defaultSelectedKeys, here is my dependency on the package.json
"@microsoft/sp-core-library": "1.11.0",
"@microsoft/sp-lodash-subset": "1.11.0",
"@microsoft/sp-office-ui-fabric-core": "^1.11.0",
"@microsoft/sp-property-pane": "1.11.0",
"@microsoft/sp-webpart-base": "1.11.0",
"@pnp/spfx-controls-react": "^2.7.0-beta.4421879",
"@types/es6-promise": "0.0.33",
"@types/react": "16.8.8",
"@types/react-dom": "16.8.3",
"@types/webpack-env": "1.13.1",
"office-ui-fabric-react": "6.214.0",
"react": "16.8.5",
"react-dom": "16.8.5"

Here is the Treeview code snippet

          <TreeView
            items={this.testdata}
            defaultExpanded={false}
            selectionMode={TreeViewSelectionMode.Multiple}
            selectChildrenIfParentSelected={true}
            showCheckboxes={true}
            treeItemActionsDisplayMode={TreeItemActionsDisplayMode.ContextualMenu}
            defaultSelectedKeys={['658','1085','1728']}
            expandToSelected={true}
            defaultExpandedChildren={false}
            onExpandCollapse={this.onExpandCollapseTree}
            onSelect={this.onStoreSelected}
            onRenderItem={this.renderCustomStoreTreeItem} 
          />

I can't able to select/deselect any items in the tree view, there are following three items are selected in the Treeview though

658
1085
1728

@YannickRe
Copy link
Contributor

The change is to not use selectChildrenIfParentSelected, but use selectChildrenMode instead. Give it SelectChildrenMode.Select | SelectChildrenMode.Unselect as a value, you’ll see it’ll work now!

@sumitdeyonline
Copy link
Author

Still, I am not able to select/deselect after setup the selectChildrenMode, here is the code snippet. Do I need to change anything else?

     <TreeView
            items={this.testdata}
            defaultExpanded={false}
            selectionMode={TreeViewSelectionMode.Multiple}
            selectChildrenMode = {SelectChildrenMode.Select | SelectChildrenMode.Unselect }
            showCheckboxes={true}
            treeItemActionsDisplayMode={TreeItemActionsDisplayMode.ContextualMenu}
            defaultSelectedKeys={['658','1085','1728']}
            expandToSelected={true}
            defaultExpandedChildren={false}
            onExpandCollapse={this.onExpandCollapseTree}
            onSelect={this.onStoreSelected}
            onRenderItem={this.renderCustomStoreTreeItem} 
      />

@YannickRe
Copy link
Contributor

@sumitdeyonline Yes, your defaultSelectedKeys is static. See this code in the TreeView component:

public componentWillReceiveProps(nextProps: ITreeViewProps): void {
const {
items,
defaultSelectedKeys
} = nextProps;
if (defaultSelectedKeys) {
const selectedItems = this.getSelectedItems(items, defaultSelectedKeys, this.checkIfChildrenShouldBeSelected(SelectChildrenMode.Update));
this.setState({
activeItems: selectedItems
});
}
}

It means that every time your component rerenders (because the parent component's state is updated), it will take the defaultSelectedKeys you passed in and select them again and none other. It essentially resets your selection, overrides the local state with the input. The naming of the parameter is misleading, it seems to signify that this is the selection only for the initial load but it will apply them on every rerender. Only a total refactor of the component can change this.

To work around this, you'll need to capture the selected items in the parent and send them back to the TreeView component. In your case it'll mean this:

  • Add a property to state selectedStoreKeys
  • In the constructor of the parent, assign your three keys to the selectedStoreKeys state property
  • Pass this.state.selectedStoreKeys to the defaultSelectedKeys property of the TreeView
  • In your this.onstoreSelected handler, read all selected keys and store them in the selectedStoreKeys state property
    The last step will trigger a parent rerender, and thus a TreeView rerender. It'll take the new selection and with my fix, your selection will stay like you want it.

@sumitdeyonline
Copy link
Author

Thank you, @YannickRe, this solution works for me, however, my initial impression was defaultSelectedKeys would impact on the initial load only, after onwards it would not impact on TreeView render. You are right, the naming of the parameter misleading us.

@YannickRe
Copy link
Contributor

@sumitdeyonline No worries, I struggled with the same thing and had to look at the source code to figure it out too. It wasn't straightforward, but I'm glad it works for you now!

@sumitdeyonline
Copy link
Author

Thank you, @YannickRe. Just for curiosity, there are any search functionality available in the TreeView, Our requirement is to search the node tree for a specific node, may be user enter some search criteria(Key only) in the text field, according to that node would be selected in Treeview

@YannickRe
Copy link
Contributor

That does not exist, but you can "easily" build in your own application. A text box where they enter the key, you add it to your this.state.selectedStoreKeys. Your app rerenders, the new key is passed and the item is selected.

@sumitdeyonline
Copy link
Author

Thank you, I have built the same functionality using the custom code, just checking anything available out of the box.

@sumitdeyonline
Copy link
Author

@YannickRe , One more question, is it possible to expand/collapse TreeView according to the selected node programmatically without reloading the page, when we enter the node key in the textbox, we are updating this.state.selectedStoreKeys as defaultSelectedKeys . Now TreeView would expand/collapse and show whatever node is entered in the textbox without reloading the page. With reloading the page it is working as expected though.

Thanks in advance.

@AJIXuMuK
Copy link
Collaborator

@sumitdeyonline - as a quick thing, instead of reloading the page, you can remove and add the TreeView.
For example, you can show <Spinner /> when you need to update the expand collapse and then by setTimeout render TreeView back:

{isLoading && <Spinner />}
{!isLoading && <TreeView ... />}

@sumitdeyonline
Copy link
Author

I have tried the same, it is not updating the TreeView(Expand/Collapse) though, here is my implementation

 return (
  this.state.loading ?
    <div><Spinner>Loading items ...</Spinner></div> :
          <TreeView
            //items={this.treeItems}
            items={this.testdata}
            defaultExpanded={false}
            selectionMode={TreeViewSelectionMode.Multiple}
           -----
           -----
          />
)

searchfilterValueItem=(item:any)=>{

this.setState({loading: true});
 // Search items and add item into default selected items 
-----
------

this.setState({loading: false});

}

@sumitdeyonline
Copy link
Author

Thank you @AJIXuMuK, after move the this.setState({loading: false}); to inside the setTimeout function, it start working

setTimeout(()=>{
  this.setState({loading: false});
},10);

@sumitdeyonline
Copy link
Author

One of our JSON datasets is returning data with the node Children: [(Uppercase C), currently TreeView interface is designed with children: [(Lowercase c). Can you please let me know how we would able to utilize the data with Uppercase C Children: [...].

  Children: [
   {
      key: "1",
      label: "Parent 1",
      selectable: true,
      Children: [
       {
          key: "3",
          label: "Child 1",

@AJIXuMuK
Copy link
Collaborator

You should implement a converter (either on back end or front end) to convert the initial data to the component's data structure

@sumitdeyonline
Copy link
Author

Thank you, we would implement data conversion in the backend.

@joelfmrodrigues
Copy link
Collaborator

@sumitdeyonline Closing this item as this should now be fixed as part of the last release. Please update to the latest release and open a new issue if you still experience problems.
@YannickRe thanks for the PR!

Many thanks for your contributions

@ManjulaMasthanvali09
Copy link

after adding treearr.push(tree); in Else part the child nodes are binding and Expand and collapse are not working
using Node-version v12.18.0 version

Please suggest on this below is the code

private async _getLinks() {
const allItems: any[] = await sp.web.lists.getByTitle(“TreeLinks”).items.getAll();
var treearr: ITreeItem[] = [];
allItems.forEach(function (v, i) {

if (v[“ParentId”] == null) {
const tree: ITreeItem = {
key: v.Id,
label: v[“Title”],
data: v[“Link”],
children: []
}
treearr.push(tree);
}
else {
const tree: ITreeItem = {
key: v.Id,
label: v[“Title”],
data: v[“Link”]
}
treearr.push(tree);
var treecol: Array = treearr.filter(function (value) { return value.key == v[“ParentId”] })
if (treecol.length != 0) {
treecol[0].children.push(tree);
}
}

console.log(v);
});
console.log(treearr);
this.setState({ TreeLinks: treearr });
}

@ManjulaMasthanvali09
Copy link

ManjulaMasthanvali09 commented Feb 10, 2022

and the tree view control is as below

public render(): React.ReactElement {
return (


  </div>
);

}

  </div>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:fixed-next-drop Issue will be fixed in upcoming release.
Projects
None yet
Development

No branches or pull requests

5 participants