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

feat: add RowDetailTemplate to/in DataGrid to implement the master/detail pattern #1711

Open
joriverm opened this issue Mar 18, 2024 · 17 comments
Labels
feature A new feature vNext For the next major version

Comments

@joriverm
Copy link
Contributor

🙋 Feature Request

In a lot of UI libraries the data grid have possibilities to expand the row, to show more details of the item that the data grid row is linked to. it is often called the master/detail pattern, and for example it can be found in a few material design :

in (blazor) fluent-ui this is missing, and to have them you have to make the table completely yourself. you can not add or change a part of the table to add the row details (and extra column) when needed.

🤔 Expected Behavior

Table to show a icon that opens/renders or closes the row detail when clicked, which's template is passed down to the datagrid.
kind of like in the mudblazor example

😯 Current Behavior

Not implemented a.t.m.

💁 Possible Solution

I have been thinking about this, and was thinking of adding a RenderFragment , called RowDetailTemplate, to the FluentDataGrid, which is then rendered as an extra row if its detail is set to be opened.
FluentDataGrid.RenderColumnHeaders could check RowDetailTemplate to see if it needs to add an additional column at the start.
FluentDataGrid.RenderRow would then also check & render RowDetailTemplate.

we (my client and me) are willing to implement this ourselves, and make a PR if this is proffered :)

🔦 Context

We are using a datagrid to display some information, but this is just some condensed version with the basics.
The row would be expanded to show or edit the information in details
in this case the info is patient allergy, which the row shows the most important data ( substance, icons to show how it would manifest in the patient etc). the details show all the medical details like the codes, categories, who reported it, how it was tested etc etc

💻 Examples

@vnbaaij
Copy link
Collaborator

vnbaaij commented Mar 18, 2024

Because we are using the datagrid web components for rendering the grid and because of using Virtualization is an option (where all items (rows in this case) need to have the same height), I believe it won't be desirable (and perhaps even impossible) to display the details inside of the grid, so that is not something we would develop ourselves or merge in from a PR.

However, the .NET Aspire team has come up with a solution for this with building a SummaryDetails component that combines a FluentDataGrid with a custom details view inside a FluentSplitter.
In a simplified form, it looks like this in code:

<div class="summary-details-container">
    <FluentSplitter Orientation="@Orientation" Collapsed="@(!_internalShowDetails)" OnResized="HandleSplitterResize"
                    Panel1Size="@_panel1Size" Panel2Size="@_panel2Size" Panel1MinSize="150px" Panel2MinSize="150px"
                    BarSize="5" @ref="_splitterRef">
        <Panel1>
            <div class="summary-container">
                @Summary
            </div>
        </Panel1>
        <Panel2>
            <div class="details-container">
                <header>
                :
               :
                </header>
                @Details
            </div>
        </Panel2>
    </FluentSplitter>
</div>

Both Summary and Details are of type Renderfragment? where summary then corresponds to a FluentDataGrid and details is a component that displays additional info from a selected row (by clicking a button in the row) in the grid. Code looks like this, again in simplified form:

<SummaryDetailsView DetailsTitle="@(SelectedResource != null ? $"{SelectedResource.ResourceType}: {GetResourceName(SelectedResource)}" : null)"
                    ShowDetails="@(SelectedResource is not null)"
                    OnDismiss="() => ClearSelectedResource()"
                    SelectedValue="@SelectedResource"
                    ViewKey="ResourcesList">
    <Summary>
        @{
            var gridTemplateColumns = HasResourcesWithCommands ? "1fr 2fr 1.25fr 1.5fr 2.5fr 2fr 1fr 1fr 1fr" : "1fr 2fr 1.25fr 1.5fr 2.5fr 2fr 1fr 1fr";
        }
        <FluentDataGrid Items="@FilteredResources" ResizableColumns="true" GridTemplateColumns="@gridTemplateColumns" RowClass="GetRowClass" Loading="_isLoading">
            <ChildContent>
                  :
                  <TemplateColumn Title="@Loc[nameof(Dashboard.Resources.Resources.ResourcesDetailsColumnHeader)]" Sortable="false" Class="no-ellipsis">
                    <FluentButton Appearance="Appearance.Lightweight"  OnClick="() => ShowResourceDetails(context)">
                       Details...
                     </FluentButton>
                </TemplateColumn>
            </ChildContent>
            <EmptyContent>
                <FluentIcon Icon="Icons.Regular.Size24.AppGeneric" />&nbsp;@Loc[nameof(Dashboard.Resources.Resources.ResourcesNoResources)]
            </EmptyContent>
        </FluentDataGrid>
    </Summary>
    <Details>
        <ResourceDetails Resource="SelectedResource" ShowSpecOnlyToggle="true" />
    </Details>
</SummaryDetailsView>

We can try to 'productize' that component in the library?

@vnbaaij
Copy link
Collaborator

vnbaaij commented Mar 19, 2024

Here is an example from Aspire Dashboard from the 'Resources' app part. The row for wich the details are being looked at is highlighted. In the bottom halfyou can see the details. In this case I filtered this view. The details view aso features some other functionality like 'View logs' but those are part of this specific details view implementation.

image

The user can also choose to have a vertical split summary/details view by clicking the icon in top right of the details (left of close details view icon):

image

The details view in this implementation usesan accordion to group the information. Agian, that is an implementation detail of this details view.

Because ofthis using a splitter, the user can resize top/bottom or left/right panels.

Thoughts? Comments?

@joriverm
Copy link
Contributor Author

joriverm commented Mar 19, 2024

Hey @vnbaaij,

thanks for the quick response. i must admit i did not think of virtualization and the limitations of using it. That makes it a bit more complex and hard...
hm.
we have made the exact same thing you are suggesting when we made a few mockups for the functional team to go over and decide what they wanted

image

however, our problem here is that space is limited, and the detail would be underneath the grid, and the grid list is variable in the amount of items which is why we were looking at either expandable cards underneath each other, or a grid with expandable rows.

the space the arrow is pointing to is the space the component would get. this is a blazor component hosted inside WPF btw

image

as for this master/detail view, i think it will be used in some projects, like in aspire as you mentioned. i have used the view/pattern in previous projects as well as it is a very good view for a list and its details.

im not sure how much more benefit you get from making the component over using the fluentsplitter manually. maybe to be added in the incubationlab? see what the response is?

the master/detail view pattern itself is one i can see us use in the future though!

@joriverm
Copy link
Contributor Author

oh,
i just looked more closely at your SummaryDetailView component usage, and it most certainly has more than just the splitter.
yes, i do think it would be beneficial to have this in the library, specially if it would be used in aspire as well!

@avojacek
Copy link

@vnbaaij Thank you for Aspire example. I did not know that they use Fluent Blazor. It is really great source for learn how to use it. Thank you a lot.

@vnbaaij vnbaaij added the feature A new feature label Apr 23, 2024
@ldsenow
Copy link

ldsenow commented Apr 29, 2024

If the virtualization is the blocker to this feature, I would personally choose having this common UI feature and must disable virtualization at the same time. It is a constraint rather not having the feature.

@vnbaaij
Copy link
Collaborator

vnbaaij commented Apr 29, 2024

@ldsenow that is not an option. Then we would need to say somethng like: "you can use the RowDetail parameter only when you have less then 'x' rows otherwise performance will degrade/app will use a huge amount of memory/etc...

With the Aspire solution we can have both. Can you explain what would be your issue with that approach (besides the size constraints mentioned by @joriverm)?

@franklupo
Copy link
Contributor

How then does MudBlazor work well even with virtualization?

@vnbaaij
Copy link
Collaborator

vnbaaij commented Jun 12, 2024

How then does MudBlazor work well even with virtualization?

They are using a completely different way of rendering a grid/rows/cells. Totally not comparable.

@franklupo
Copy link
Contributor

Hi,
I created a new column HierarchyColumn to collapse/expand a row. This saves the expanded object in a collection.
When clicking on Icon the expanded/collapsed icon is updated.

In FluentDataGrid i create a RowDetailTemplate.

In FluentDataGrid.RenderRow I added view checking if expanded

....
<FluentDataGridRow..... >
.........
    @if (RowDetailTemplate != null && HierarchyColumn != null && HierarchyColumn.IsExpanded(item))
    {
        @RowDetailTemplate(item)
    }
</FluentDataGridRow>

In FluentDataGridRow I added the control of HandleOnRowClick to exclude SelectionColumn if expand/collapse is clicked.

if (Owner.Grid.HierarchyColumn != null)
{
....
}

For me work, not in virtualized.

bets regards

@franklupo
Copy link
Contributor

image

@joriverm
Copy link
Contributor Author

joriverm commented Jun 20, 2024

@franklupo : as a test we did something similar, but like vincent mentioned, virtualised tables tend to be broken by such methods. try this and see.
when i tried it my table row's height was all fucked :)

@franklupo
Copy link
Contributor

I confirm in virtualized was all fucked :)
Without virtualized work. For me virtualized in this case is not necessary.

I saw that Mudblazor solved it another way https://github.com/MudBlazor/MudBlazor/blob/7e925205e9f83e9907a1a3aa20a7a11c014502e9/src/MudBlazor/Components/DataGrid/MudDataGrid.razor#L233

@vnbaaij
Copy link
Collaborator

vnbaaij commented Jun 20, 2024

When using standard Blazor Virtualize (which we do), all items need to be the same size (height).
This is why we want to (and probably will) solve it with a SummaryDetailView

@franklupo
Copy link
Contributor

in my case I can't I don't have enough space and I should have more elements open

@vnbaaij vnbaaij added the vNext For the next major version label Sep 2, 2024
@RobDene
Copy link

RobDene commented Sep 10, 2024

Personally agree with @franklupo - having a feature that's incompatible with another isn't a deal breaker for people - it offers additional flexibility just with a caveat.

@RobDene
Copy link

RobDene commented Sep 11, 2024

Just trying to look for a solution: what happens if the default view is multiline and the additional lines are hidden? This would satisfy the requirements of the virtualisation need for all items to be the same height ?
Then a method to expand/shrink the hidden multi-lines wouldn't be an issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature A new feature vNext For the next major version
Projects
None yet
Development

No branches or pull requests

6 participants