desmondische
desmondische

Reputation: 266

Blazor QuickGrid: how to create a column without populating RenderFragment?

I am still exploring what Blazor's QuickGrid can do.

And I faced one annoying problem here. I want to add one more column that will be used to render checkboxes in the header and in the body. I want this column to be rendered by providing only type parameter, like this:

<QuickGrid Data="@data">
    <CheckboxColumn Title="Checkbox" /> // my custom column
    <PropertyColumn Property="@(c => c.Id)" Format="C" />
    <PropertyColumn Property="@(c => c.Name)" />
    <TemplateColumn Title="Actions">
        <button>@context.Price</button>
    </TemplateColumn>
</QuickGrid>

From the docs we know that we may define columns by adding components derived from the ColumnBase<TGridItem> base class. So, I created my custom class like this:

public class CheckboxColumn<TGridItem> : ColumnBase<TGridItem>
{
    // abstract method implementation
}

The problem is that in the end, the grid doesn't renders my column (means that in the browser I can see all of the columns except the first one). Why?

Remarks:

  1. I tried to debug and examine what's happening there. On the first render of the grid, I can see that all 4 columns were collected by this call Grid.AddColumn(this) in the ColumnBase.razor. But then, due to invoke of a callback, the grid re-renders, clears the collection of the columns, and renders @ChildContent again, means that Grid.AddColumn(this) gets called again. But this time, the first this is the 2nd column.

So, in short: on initial render we get all 4 columns -> at specific time re-rendering happens -> collection of columns gets cleared -> we get only 3 columns (all except the first one)

I hope you could follow the logic.

  1. Since CheckboxColumn is derived from ColumnBase, we can use, for example, a HeaderTemplate which is a RenderFragment<>. If we provide something in the HeaderTemplate for CheckboxColumn -- everything renders fine. But I don't want to provide any RenderFragments in there.

UPD-1 If Align parameter is provided to CheckboxColumn -- everything is fine! But it still doesn't answer the question for me...

UPD-2 If I am not mistaken, this statement (All of the parameters are from a set of known types† or any primitive type that hasn't changed since the previous set of parameters were set.) answers, why my CheckboxColumn does not get re-rendered. So how can I force re-render?

Upvotes: 3

Views: 7084

Answers (1)

Vaclav Elias
Vaclav Elias

Reputation: 4151

I would like myself an empty column which I use for CSS index number but I believe it is not possible at the moment, due to current QuickGrid implementation so we have to do the ceremony for now 🤣.

I have created some bare minimum for you which works for me, two examples:

<EmptyColumn Title="#" TGridItem="CorporateUserDto" Property="new()" />
<EmptyColumn2 Title="#" Property="new()" />

The first one is passing the type TGridItem, and so it is generic.

The second one has a hard coded type, which you will see below but must be the same type as your TGridItem otherwise it won't work.

public class EmptyColumn<TGridItem> : ColumnBase<TGridItem>
{
    /// <summary>
    /// Dummy Property otherwise it doesn't render
    /// </summary>
    [Parameter] public TGridItem? Property { get; set; }

    protected override void CellContent(RenderTreeBuilder builder, TGridItem item) 
    => builder.AddContent(0, “Hi”);
}

public class EmptyColumn2 : ColumnBase<CorporateUserDto>
{
    /// <summary>
    /// Dummy Property otherwise it doesn't render
    /// </summary>
    [Parameter] public CorporateUserDto? Property { get; set; }

    protected override void CellContent(RenderTreeBuilder builder, CorporateUserDto item)
    => builder.AddContent(0, “Hello”);
}

Another example is this one, which is again flexible as I can select any boolean property I want so it is type checked.

<CheckboxColumn TGridItem="CorporateUserDto" Property="@(c => c.IsLondon)" />

I used this implementation for CheckboxColumn , but because it is just boolean, it is simlified https://github.com/aspnet/AspLabs/blob/main/src/QuickGrid/src/Microsoft.AspNetCore.Components.QuickGrid/Columns/PropertyColumn.cs

An alternative or combination with the custom columns is the flexibility to add them dynamically in the easiest way, e.g. using some manager e.g. we can add a column as simply as calling this AddSpaceshipId().

@code {
    private bool _isLoading = true;        
    private List<SpaceshipDto> _items = new();
    private ColumnManager<SpaceshipDto> _columnManager = new();

    protected override async Task OnInitializedAsync()
    {
        _columnManager.AddSpaceshipId();
        _columnManager.AddSpaceshipName();
        _columnManager.Add(new() { Property = p => p.LastDepartureDate, Title = "Last Departure" });
        _columnManager.Add(new() { Property = p => p.LastDepartureDays, Title = "Days", Align = Align.Center });

        _items = await Service.GetSpaceships();

        _isLoading = false;
    }
}

And then we can render it here

<QuickGrid Items=“@_items.AsQueryable()” Class=“table table-sm table-index table-striped small table-blazor table-fit mb-0 table-thead-sticky” Theme=“earth”>
   <EmptyColumn Title=“#” TGridItem=“SpaceshipDto” Property=“new()” />
    @foreach (var col in _columnManager.Get())
    {
        <PropertyColumn Title=“@col.Title”
           Property=“@col.Property”
           Sortable=“@col.Sortable”
           Align=“@col.Align” />
    }
</QuickGrid>

I am preparing a blog post regarding the ColumnManager. I will leave a link in the comment once it is done.

Upvotes: 0

Related Questions