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

[HxGrid] Adding attributes on TR - HxGrid.TableRowAdditionalAttributes + splatting #929

Merged
merged 2 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@

<table class="@GetTableElementCssClass(_totalCount > 0)">
<thead class="@TableHeaderCssClassEffective">
<tr class="@HeaderRowCssClassEffective">
<tr class="@HeaderRowCssClassEffective"
@attributes="HeaderRowAdditionalAttributes">
@{
GridHeaderCellContext gridHeaderCellContext = CreateGridHeaderCellContext();
}
Expand Down Expand Up @@ -137,6 +138,7 @@
ItemRowCssClassEffective,
ItemRowCssClassSelector?.Invoke(item),
((SelectionEnabled && (item != null) && item.Equals(SelectedDataItem)) ? "table-active" : null))"
@attributes="ItemRowAdditionalAttributesSelectorEffective(item)"
@onclick="async () => await HandleSelectOrMultiSelectDataItemClick(item)"
@onclick:stopPropagation>

Expand All @@ -156,6 +158,7 @@
<tr @key="@(ItemKeySelector(item))"
height="@((ContentNavigationModeEffective == GridContentNavigationMode.InfiniteScroll) ? rowHeight : null)"
class="@CssClassHelper.Combine(ItemRowCssClassEffective, ItemRowCssClassSelector?.Invoke(item))"
@attributes="ItemRowAdditionalAttributesSelectorEffective(item)"
@onclick:stopPropagation>

@foreach (IHxGridColumn<TItem> column in columnsToRender)
Expand Down Expand Up @@ -247,7 +250,8 @@
&& shouldRenderFooter)
{
<tfoot>
<tr class="@FooterRowCssClassEffective">
<tr class="@FooterRowCssClassEffective"
@attributes="FooterRowAdditionalAttributes">
@for (int i = 0; i < footerTemplates.Length; i++) // do not use foreach, we need to use i as a key as footerTemplates can contain duplicates
{
<td @key="@i" class="@footerTemplates[i].CssClass">@footerTemplates[i].Template</td>
Expand Down
58 changes: 58 additions & 0 deletions Havit.Blazor.Components.Web.Bootstrap/Grids/HxGrid.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,64 @@ public partial class HxGrid<TItem> : ComponentBase, IDisposable
[Parameter] public IconBase SortDescendingIcon { get; set; }
protected IconBase SortDescendingIconEffective => SortDescendingIcon ?? GetSettings()?.SortDescendingIcon ?? GetDefaults().SortDescendingIcon;

/// <summary>
/// Defines a function that returns additional attributes for a specific <c>tr</c> element based on the item it represents.
/// This allows for custom behavior or event handling on a per-row basis.
/// </summary>
/// <remarks>
/// If both <see cref="ItemRowAdditionalAttributesSelector"/> and <see cref="ItemRowAdditionalAttributes"/> are specified,
/// both dictionaries are combined into one.
/// Note that there is no prevention of duplicate keys, which may result in a <see cref="System.ArgumentException"/>.
/// </remarks>
[Parameter] public Func<TItem, Dictionary<string, object>> ItemRowAdditionalAttributesSelector { get; set; }

/// <summary>
/// Provides a dictionary of additional attributes to apply to all body <c>tr</c> elements in the grid.
/// These attributes can be used to customize the appearance or behavior of rows.
/// </summary>
/// <remarks>
/// If both <see cref="ItemRowAdditionalAttributesSelector"/> and <see cref="ItemRowAdditionalAttributes"/> are specified,
/// both dictionaries are combined into one.
/// Note that there is no prevention of duplicate keys, which may result in a <see cref="System.ArgumentException"/>.
/// </remarks>
[Parameter] public Dictionary<string, object> ItemRowAdditionalAttributes { get; set; }

/// <summary>
/// Provides a dictionary of additional attributes to apply to the header <c>tr</c> element of the grid.
/// This allows for custom styling or behavior of the header row.
/// </summary>
[Parameter] public Dictionary<string, object> HeaderRowAdditionalAttributes { get; set; }

/// <summary>
/// Provides a dictionary of additional attributes to apply to the footer <c>tr</c> element of the grid.
/// This allows for custom styling or behavior of the footer row.
/// </summary>
[Parameter] public Dictionary<string, object> FooterRowAdditionalAttributes { get; set; }

/// <summary>
/// Determines the effective additional attributes for a given data row, combining both the global and per-item attributes.
/// </summary>
/// <param name="item">The data item for the current row.</param>
/// <returns>A dictionary of additional attributes to apply to the row.</returns>
/// <exception cref="System.ArgumentException">Thrown when there are duplicate keys in the combined dictionaries.</exception>
private Dictionary<string, object> ItemRowAdditionalAttributesSelectorEffective(TItem item)
{
if (ItemRowAdditionalAttributesSelector == null)
{
return ItemRowAdditionalAttributes;
}
else if (ItemRowAdditionalAttributes == null)
{
return ItemRowAdditionalAttributesSelector(item);
}
else
{
return ItemRowAdditionalAttributes.Concat(ItemRowAdditionalAttributesSelector(item)).ToDictionary(x => x.Key, x => x.Value);
}

}


/// <summary>
/// Retrieves the default settings for the grid. This method can be overridden in derived classes
/// to provide different default settings or to use a derived settings class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6562,6 +6562,48 @@
Icon to indicate the descending sort direction in the column header. This icon is shown when a column is sorted in descending order.
</summary>
</member>
<member name="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.ItemRowAdditionalAttributesSelector">
<summary>
Defines a function that returns additional attributes for a specific <c>tr</c> element based on the item it represents.
This allows for custom behavior or event handling on a per-row basis.
</summary>
<remarks>
If both <see cref="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.ItemRowAdditionalAttributesSelector"/> and <see cref="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.ItemRowAdditionalAttributes"/> are specified,
both dictionaries are combined into one.
Note that there is no prevention of duplicate keys, which may result in a <see cref="T:System.ArgumentException"/>.
</remarks>
</member>
<member name="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.ItemRowAdditionalAttributes">
<summary>
Provides a dictionary of additional attributes to apply to all body <c>tr</c> elements in the grid.
These attributes can be used to customize the appearance or behavior of rows.
</summary>
<remarks>
If both <see cref="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.ItemRowAdditionalAttributesSelector"/> and <see cref="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.ItemRowAdditionalAttributes"/> are specified,
both dictionaries are combined into one.
Note that there is no prevention of duplicate keys, which may result in a <see cref="T:System.ArgumentException"/>.
</remarks>
</member>
<member name="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.HeaderRowAdditionalAttributes">
<summary>
Provides a dictionary of additional attributes to apply to the header <c>tr</c> element of the grid.
This allows for custom styling or behavior of the header row.
</summary>
</member>
<member name="P:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.FooterRowAdditionalAttributes">
<summary>
Provides a dictionary of additional attributes to apply to the footer <c>tr</c> element of the grid.
This allows for custom styling or behavior of the footer row.
</summary>
</member>
<member name="M:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.ItemRowAdditionalAttributesSelectorEffective(`0)">
<summary>
Determines the effective additional attributes for a given data row, combining both the global and per-item attributes.
</summary>
<param name="item">The data item for the current row.</param>
<returns>A dictionary of additional attributes to apply to the row.</returns>
<exception cref="T:System.ArgumentException">Thrown when there are duplicate keys in the combined dictionaries.</exception>
</member>
<member name="M:Havit.Blazor.Components.Web.Bootstrap.HxGrid`1.GetDefaults">
<summary>
Retrieves the default settings for the grid. This method can be overridden in derived classes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public static class DependencyInjectionExtensions
public static IServiceCollection AddClientServices(this IServiceCollection services)
{
services.AddHxServices();
services.AddTransient<IDemoDataService, DemoDataService>();

return services;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
global using Microsoft.AspNetCore.Components;

global using Havit.Blazor.Components.Web;
global using Havit.Blazor.Components.Web.Bootstrap;
global using Havit.Blazor.Components.Web.Bootstrap;

global using Havit.Blazor.Documentation.DemoData;
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@
<ProjectReference Include="..\..\Havit.Blazor.Components.Web.Bootstrap\Havit.Blazor.Components.Web.Bootstrap.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\..\Havit.Blazor.Documentation\DemoData\**\*.*">
<Link>DemoData\%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
@page "/HxGrid_DragDropRows"
@rendermode InteractiveServer

<h3>HxGrid_DragDropRows</h3>

<HxGrid @ref="grid"
TItem="Person"
DataProvider="GetGridData"
PageSize="5"
Responsive="true"
HeaderRowAdditionalAttributes="HeaderRowAdditionalAttributes "
ItemRowAdditionalAttributes="ItemRowAdditionalAttributes"
ItemRowAdditionalAttributesSelector="EmployeeRowAttributes">
<Columns>
<HxGridColumn>
<ItemTemplate>
<HxIcon Icon="BootstrapIcon.GripVertical" />
</ItemTemplate>
</HxGridColumn>
<HxGridColumn HeaderText="Name" ItemTextSelector="employee => employee.Name" />
<HxGridColumn HeaderText="Phone" ItemTextSelector="employee => employee.Initials" />
</Columns>
</HxGrid>

@code {
HxGrid<Person> grid;
private record class Person(string Name, string Initials)
{
public int Position { get; set; }
};
private List<Person> people;

protected override void OnInitialized()
{
people = new List<Person>
{
new Person("Starr Ringo", "RS") { Position = 1 },
new Person("Lennon John", "JL") { Position = 2 },
new Person("McCartney Paul", "PMC") { Position = 3 },
new Person("Harrison George", "GH") { Position = 4 }
};
}

Person clickedEmployee;
Dictionary<string, object> HeaderRowAdditionalAttributes = new() { { "data-row-type", "header" } };
Dictionary<string, object> ItemRowAdditionalAttributes = new() { { "draggable", "true" }, { "ondragover", "event.preventDefault();" } };

Dictionary<string, object> EmployeeRowAttributes(Person item)
{
return new() {
{"ondragstart", EventCallback.Factory.Create<DragEventArgs>(this, (e) => HandleDragStart(item, e))},
{"ondrop", EventCallback.Factory.Create<DragEventArgs>(this, () => HandleDrop(item))},
// {"ondragenter", EventCallback.Factory.Create<DragEventArgs>(this,(e) => HandleDragEnter(item, e)) },
// {"ondragleave", EventCallback.Factory.Create<DragEventArgs>(this,HandleDragLeave) },
// {"ondragend", EventCallback.Factory.Create<DragEventArgs>(this,HandleDragEnd) },
};
}

private void SetEmpoloyee(Person employee)
{
clickedEmployee = employee;
}

private Task<GridDataProviderResult<Person>> GetGridData(GridDataProviderRequest<Person> request)
{
return Task.FromResult(new GridDataProviderResult<Person>()
{
Data = people.OrderBy(x => x.Position).ToList(),
TotalCount = people?.Count
});
}

private Person draggedItem;


private void HandleDragStart(Person item, DragEventArgs e)
{
draggedItem = item;
}

private async Task HandleDrop(Person item)
{
if (draggedItem == null) return;


var draggedItemPosition = draggedItem.Position;

if (draggedItemPosition == item?.Position) return;
draggedItem.Position = item.Position;
item.Position = draggedItemPosition;


await grid.RefreshDataAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@page "/HxGrid_RowAdditionalAttributes"
@rendermode InteractiveServer
@inject IDemoDataService DemoDataService

<h3>HxGrid_RowAdditionalAttributes</h3>

Selectet phone: @clickedEmployee?.Phone
<HxGrid TItem="EmployeeDto" DataProvider="GetGridData" PageSize="5" Responsive="true"
HeaderRowAdditionalAttributes="headerRowAdditionalAttributes"
FooterRowAdditionalAttributes="footerRowAdditionalAttributes"
ItemRowAdditionalAttributes="itemRowAdditionalAttributes"
ItemRowAdditionalAttributesSelector="EmployeeRowAttributes">
<Columns>
<HxGridColumn HeaderText="Name" ItemTextSelector="employee => employee.Name" />
<HxGridColumn HeaderText="Phone" ItemTextSelector="employee => employee.Phone" />
<HxGridColumn HeaderText="Salary" ItemTextSelector="@(employee => employee.Salary.ToString("c0"))" ItemCssClass="text-end" HeaderCssClass="text-end" />
<HxGridColumn HeaderText="Position" ItemTextSelector="employee => employee.Position" />
<HxGridColumn HeaderText="Location" ItemTextSelector="employee => employee.Location" />
</Columns>
</HxGrid>

@code {
EmployeeDto clickedEmployee;
Dictionary<string, object> headerRowAdditionalAttributes = new() { { "data-row-type", "header" } };
Dictionary<string, object> footerRowAdditionalAttributes = new() { { "data-row-type", "footer" } };
Dictionary<string, object> itemRowAdditionalAttributes = new() { { "data-row-type", "row" }, { "data-other", "dummy" } };

private Dictionary<string, object> EmployeeRowAttributes(EmployeeDto e)
{
return new() {
{ "data-name", e?.Name },
{ "onmouseup", EventCallback.Factory.Create<MouseEventArgs>(this,x => clickedEmployee = e) } };
}

private async Task<GridDataProviderResult<EmployeeDto>> GetGridData(GridDataProviderRequest<EmployeeDto> request)
{
return new GridDataProviderResult<EmployeeDto>()
{
Data = await DemoDataService.GetEmployeesDataFragmentAsync(request.StartIndex, request.Count, request.CancellationToken),
TotalCount = await DemoDataService.GetEmployeesCountAsync(request.CancellationToken)
};
}
}