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

TreeView issue in v7.0.0-preview4 with multi selection #9126

Closed
henon opened this issue Jun 6, 2024 · 17 comments · Fixed by #9151
Closed

TreeView issue in v7.0.0-preview4 with multi selection #9126

henon opened this issue Jun 6, 2024 · 17 comments · Fixed by #9151

Comments

@henon
Copy link
Collaborator

henon commented Jun 6, 2024

Reported by sardar97 in issue comment: #8447 (comment)

There is an issue with TreeView component in v7.0.0-preview4 when I use multi selection and I have child and
I bind-SelectedValues every thing is working fine but the only problem it have is when I want to load some data to the SelectedValues it will not check the chebox. even the ICollection of the SelectedValues has loaded the data but will not check the checkboxes in the tree view. I will show some code and screenshot to more explanation.
and in my opinion the problem is Binding SelectedValues between the parent and child.

<MudTreeView Items="@TreeItems" ExpandOnClick="false" Hover="true" SelectionMode="SelectionMode.MultiSelection"
                          @bind-SelectedValues="_SelectedItem">
                <ItemTemplate>
                    <MudTreeViewItem @bind-Expanded="@context.Expanded" Value="@context"
                                     Text="@context.Title"  >
                        @foreach (var item in context.ChildItems)
                        {
                            <MudTreeViewItem Value="@item" 
                                             Text="@item.Title"/>
                        }
                    </MudTreeViewItem>
                </ItemTemplate>
            </MudTreeView>
private async Task getAllRoles()
    {
        var result = await _roleManager.GetClaimsAsync(_IdentityRole);
        if (result is not null)
        {
            var actions = new List<string>();
            foreach (var item in result.ToList())
            {
                actions.Add(item.Value);
            }
            // Step 1: Split each string into parent and child parts
            var splitActions = actions
                .Select(action => new
                {
                    Parent = action.Split('.')[0],
                    Child = action.Split('.')[1]
                });
    
            // Step 2: Group the items by the parent
            var groupedActions = splitActions
                .GroupBy(action => action.Parent);
             
            var _newItem = new List<TreeItemData>();
            // Step 3: Iterate over the grouped data and populate _newItem
            foreach (var group in groupedActions)
            {
                var parentItem = new TreeItemData(group.Key, group.Key, true)
                {
                    ChildItems = new()
                };
                foreach (var action in group)
                {
                    var childItem = new TreeItemData(action.Child, group.Key, false);
                    parentItem.ChildItems.Add(childItem); 
                }
    
                _newItem.Add(parentItem);
            }
    
            _SelectedItem = new ReadOnlyCollection<TreeItemData>(_newItem);
        }
    }
Screen.Recording.2024-06-06.at.7.20.14.AM.mov

Originally posted by @sardar97 in #8447 (comment)

@henon
Copy link
Collaborator Author

henon commented Jun 6, 2024

@sardar97 I'll fix your issue but I need your help. To be honest, from your video I don't understand what is going on at all. Can you create a minimal example code that reproduces your problem without all your application complexity? I can use that as a test case for creating a fix.

Since TryMB is still on v6.x.x you could checkout our dev branch and add a simple example to our treeview docs that exhibits the behavior you reported. Then either PR that example and tag me or post the example code here in this issue

@sardar97
Copy link

sardar97 commented Jun 6, 2024

@sardar97 I'll fix your issue but I need your help. To be honest, from your video I don't understand what is going on at all. Can you create a minimal example code that reproduces your problem without all your application complexity? I can use that as a test case for creating a fix.

Since TryMB is still on v6.x.x you could checkout our dev branch and add a simple example to our treeview docs that exhibits the behavior you reported. Then either PR that example and tag me or post the example code here in this issue

see it here
I just used one of the examples in dev.mudblazor.com treeview docs

@henon
Copy link
Collaborator Author

henon commented Jun 6, 2024

I understand your problem now. Your MudTreeView has T="TreeItemData". When you set SelectedValues to some other objects of TreeItemData the treeview will find that it doesn't have matching values in its tree and thus nothing happens. You need to either set a comparer or implement GetHashCode() and Equals() on your TreeItemData class.

@henon
Copy link
Collaborator Author

henon commented Jun 6, 2024

@ScarletKuro The problem we have here is related to our discussion a while ago. Treeview has a parameter

        [Parameter]
        [Category(CategoryTypes.TreeView.Data)]
        public IReadOnlyCollection<T>? Items { get; set; } = Array.Empty<T>();

Which are then rendered in the treeview razor using the item template:

            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }

The problem here is that the Items parameter now forces the treeview to become T="TreeViewData" instead of for instance T="string" which would be better suited for SelectedValues.

I think we should provide a standard TreeItemData<T> class which our users can inherit from and change Items from type T to TreeItemData<T>.

Do you concur?

@sardar97
Copy link

sardar97 commented Jun 6, 2024

@ScarletKuro The problem we have here is related to our discussion a while ago. Treeview has a parameter

        [Parameter]
        [Category(CategoryTypes.TreeView.Data)]
        public IReadOnlyCollection<T>? Items { get; set; } = Array.Empty<T>();

Which are then rendered in the treeview razor using the item template:

            @foreach (var item in Items)
            {
                @ItemTemplate(item)
            }

The problem here is that the Items parameter now forces the treeview to become T="TreeViewData" instead of for instance T="string" which would be better suited for SelectedValues.

I think we should provide a standard TreeItemData<T> class which our users can inherit from and change Items from type T to TreeItemData<T>.

Do you concur?

yes I am, that really make sense.

@sardar97
Copy link

sardar97 commented Jun 6, 2024

I understand your problem now. Your MudTreeView has T="TreeItemData". When you set SelectedValues to some other objects of TreeItemData the treeview will find that it doesn't have matching values in its tree and thus nothing happens. You need to either set a comparer or implement GetHashCode() and Equals() on your TreeItemData class.

I tried this with my own codes it make sense for the parent only not for the child!

 public class TreeItemData
    {
        public string Title { get; set; }
        public string ParentName { get; set; }
        public bool IsParent { get; set; }
        public bool Expanded { get; set; }
        public HashSet<TreeItemData> ChildItems { get; set; }
    
        public TreeItemData(string title,string parentName,bool isParent)
        {
            Title = title; 
            ParentName = parentName;
            IsParent = isParent; 
        }
        
        public override bool Equals(object? obj)
        {
            return obj is TreeItemData data &&
                   Title == data.Title &&
                   ParentName == data.ParentName &&
                   IsParent == data.IsParent;
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(Title, ParentName, IsParent);
        }
    }
Screenshot 2024-06-06 at 9 53 08 AM

@henon
Copy link
Collaborator Author

henon commented Jun 6, 2024

I think it would work if you just used the Title for comparison.

        public override bool Equals(object? obj)
        {
            return obj is TreeItemData data &&
                   Title == data.Title;
        }

        public override int GetHashCode()
        {
            return Title.GetHashCode();
        }

Edit: or if they are not unique you'll need some kind of unique ID

@sardar97
Copy link

sardar97 commented Jun 6, 2024

I think it would work if you just used the Title for comparison.

        public override bool Equals(object? obj)
        {
            return obj is TreeItemData data &&
                   Title == data.Title;
        }

        public override int GetHashCode()
        {
            return Title.GetHashCode();
        }

Edit: or if they are not unique you'll need some kind of unique ID

Actually I don't have unique ID in my case and let me explain it.

I have this table which is from asp net core Identity and I want to get only claim value
Screenshot 2024-06-06 at 10 14 07 AM

and then separate claim values by "." like Kitchen is parent and creat,read,update,delete . however in this case the parent is kind of unique because it will never repeat for each role.
well again it is what I want to do is that I want group by parent and show creat,read,update,delete for child.
I hope this would be clear for you 😅

@henon
Copy link
Collaborator Author

henon commented Jun 6, 2024

The claim value looks like a suitably unique ID

@sardar97
Copy link

sardar97 commented Jun 6, 2024

The claim value looks like a suitably unique ID

yeah but the problem is that I have to separate them for better user friendly ui and I don't really know how to handle it :(

@henon
Copy link
Collaborator Author

henon commented Jun 6, 2024

It is easy. Add public string ID { get; set; } to class TreeItemData and save the claim value in the ID. Then use it for Equals and GetHashCode()

@sardar97
Copy link

sardar97 commented Jun 6, 2024

@henon look at this shadow issue as well.

Screen.Recording.2024-06-06.at.3.04.33.PM.mov

@henon
Copy link
Collaborator Author

henon commented Jun 6, 2024

Browser rendering issue? I don't see how this could be a treeview bug.
treeview card shadow

@sardar97
Copy link

sardar97 commented Jun 6, 2024

yeah it is only in Safari has this issue.

@ScarletKuro
Copy link
Member

Do you concur?

Yes.
Do we want to add it in v7 or v8?

@sardar97
Copy link

sardar97 commented Jun 8, 2024

Do you concur?

Yes.

Do we want to add it in v7 or v8?

Imo v7 would be better

@henon
Copy link
Collaborator Author

henon commented Jun 8, 2024

I plan to PR it this weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants