From 13a2a7802cefd3128458c780e73b36beeeb208e7 Mon Sep 17 00:00:00 2001 From: Paul Welter Date: Sat, 13 Jan 2024 22:50:52 -0600 Subject: [PATCH] add CellAttribute and RowAttribute --- samples/Sample.ClientSide/Program.cs | 16 ++++- samples/Sample.Core/Models/Bank.cs | 28 ++++++++ samples/Sample.Core/Models/StateLocation.cs | 8 ++- .../Pages/DataGrid/Examples/Banks.razor | 56 ++++++++++++++++ .../Sample.Core/Pages/DataGrid/Index.razor | 4 ++ samples/Sample.Core/Services/GitHubClient.cs | 3 +- .../Sample.Core/Services/RandomDataClient.cs | 33 +++++++++ src/LoreSoft.Blazor.Controls/DataColumn.cs | 67 ++++++++++--------- src/LoreSoft.Blazor.Controls/DataGrid.razor | 36 ++++++---- .../DataGrid.razor.cs | 20 +++--- 10 files changed, 211 insertions(+), 60 deletions(-) create mode 100644 samples/Sample.Core/Models/Bank.cs create mode 100644 samples/Sample.Core/Pages/DataGrid/Examples/Banks.razor create mode 100644 samples/Sample.Core/Services/RandomDataClient.cs diff --git a/samples/Sample.ClientSide/Program.cs b/samples/Sample.ClientSide/Program.cs index e497a139..620b2191 100644 --- a/samples/Sample.ClientSide/Program.cs +++ b/samples/Sample.ClientSide/Program.cs @@ -27,11 +27,21 @@ public static async Task Main(string[] args) .AddHttpClient() .AddHttpMessageHandler(); - services.AddScoped(sp => sp.GetRequiredService().CreateClient("default")); + services + .AddHttpClient() + .AddHttpMessageHandler(); - services.AddProgressBar(); + services.AddScoped(sp => sp + .GetRequiredService() + .CreateClient("default") + ); + + services + .AddProgressBar(); - await builder.Build().RunAsync(); + await builder + .Build() + .RunAsync(); } } } diff --git a/samples/Sample.Core/Models/Bank.cs b/samples/Sample.Core/Models/Bank.cs new file mode 100644 index 00000000..b6955222 --- /dev/null +++ b/samples/Sample.Core/Models/Bank.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace Sample.Core.Models +{ + public class Bank + { + [JsonPropertyName("id")] + public int Id { get; set; } + + [JsonPropertyName("uid")] + public Guid Identifier { get; set; } + + [JsonPropertyName("account_number")] + public string AccountNumber { get; set; } + + [JsonPropertyName("iban")] + public string IBAN { get; set; } + + [JsonPropertyName("bank_name")] + public string BankName { get; set; } + + [JsonPropertyName("routing_number")] + public string RoutingNumber { get; set; } + + [JsonPropertyName("swift_bic")] + public string SwiftBIC { get; set; } + } +} \ No newline at end of file diff --git a/samples/Sample.Core/Models/StateLocation.cs b/samples/Sample.Core/Models/StateLocation.cs index 33977c2b..f6fe4974 100644 --- a/samples/Sample.Core/Models/StateLocation.cs +++ b/samples/Sample.Core/Models/StateLocation.cs @@ -1,4 +1,6 @@ -namespace Sample.Core.Models +using Sample.Core.Pages.DataGrid.Examples; + +namespace Sample.Core.Models { public class StateLocation { @@ -8,7 +10,7 @@ public StateLocation(string name, string value) Value = value; } - public string Name { get; set; } - public string Value { get; set; } + public string Name { get; set; } + public string Value { get; set; } } } \ No newline at end of file diff --git a/samples/Sample.Core/Pages/DataGrid/Examples/Banks.razor b/samples/Sample.Core/Pages/DataGrid/Examples/Banks.razor new file mode 100644 index 00000000..7e5d07b8 --- /dev/null +++ b/samples/Sample.Core/Pages/DataGrid/Examples/Banks.razor @@ -0,0 +1,56 @@ +@using Sample.Core.Services +@using Sample.Core.Models + +@inject RandomDataClient RandomDataClient; + +

Banks

+ + + + + + + + + + + + + +
@grid.Pager.StartItem - @grid.Pager.EndItem of @grid.Pager.Total
+
+
+ + +@code { + public ICollection Data { get; set; } = new List(); + + private DataGrid DataGrid { get; set; } + + protected async override Task OnInitializedAsync() + { + var results = await RandomDataClient.GetBanks(); + + Data = results; + + // triger refresh + StateHasChanged(); + await DataGrid.RefreshAsync(true); + } + + private Dictionary CellAttributes(Bank bank) + { + return new Dictionary + { + { "data-key-" + bank.Id, "Test " + bank.BankName } + }; + } + + private Dictionary RowAttributes(Bank bank) + { + return new Dictionary + { + { "data-row-" + bank.Id, "Test " + bank.BankName } + }; + } +} diff --git a/samples/Sample.Core/Pages/DataGrid/Index.razor b/samples/Sample.Core/Pages/DataGrid/Index.razor index ba7db4b5..de22a2d3 100644 --- a/samples/Sample.Core/Pages/DataGrid/Index.razor +++ b/samples/Sample.Core/Pages/DataGrid/Index.razor @@ -21,6 +21,10 @@ +
+ + + @code { } diff --git a/samples/Sample.Core/Services/GitHubClient.cs b/samples/Sample.Core/Services/GitHubClient.cs index c0af56ac..c886ea6e 100644 --- a/samples/Sample.Core/Services/GitHubClient.cs +++ b/samples/Sample.Core/Services/GitHubClient.cs @@ -1,4 +1,5 @@ using Sample.Core.Models.GitHub; + using System; using System.Net.Http; using System.Net.Http.Headers; @@ -39,6 +40,4 @@ public async Task> SearchRepositories(string text, int? return result; } } - - } diff --git a/samples/Sample.Core/Services/RandomDataClient.cs b/samples/Sample.Core/Services/RandomDataClient.cs new file mode 100644 index 00000000..34170912 --- /dev/null +++ b/samples/Sample.Core/Services/RandomDataClient.cs @@ -0,0 +1,33 @@ +using Sample.Core.Models; + +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Net.Mime; + +namespace Sample.Core.Services +{ + public class RandomDataClient + { + public HttpClient HttpClient { get; } + + public RandomDataClient(HttpClient httpClient) + { + httpClient.BaseAddress = new Uri("https://random-data-api.com/"); + + var mimeTypeHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json); + httpClient.DefaultRequestHeaders.Accept.Add(mimeTypeHeader); + + HttpClient = httpClient; + } + + public async Task> GetBanks(int size = 100) + { + var url = $"/api/v2/banks"; + + if (size > 0) + url += $"?size={size}"; + + return await HttpClient.GetFromJsonAsync>(url); + } + } +} diff --git a/src/LoreSoft.Blazor.Controls/DataColumn.cs b/src/LoreSoft.Blazor.Controls/DataColumn.cs index c559fcbe..b2fffb6f 100644 --- a/src/LoreSoft.Blazor.Controls/DataColumn.cs +++ b/src/LoreSoft.Blazor.Controls/DataColumn.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using System.Text; using System.Text.RegularExpressions; + using Microsoft.AspNetCore.Components; namespace LoreSoft.Blazor.Controls @@ -12,14 +13,15 @@ public class DataColumn : ComponentBase { private Func _propertyAccessor; private string _propertyName; - private int? _sortIndex; - private bool? _sortDescending; [CascadingParameter(Name = "Grid")] protected DataGrid Grid { get; set; } [Parameter(CaptureUnmatchedValues = true)] - public Dictionary Attributes { get; set; } + public Dictionary UnmatchedAttributes { get; set; } + + [Parameter] + public Func> CellAttributes { get; set; } [Parameter] public Expression> Property { get; set; } @@ -50,18 +52,10 @@ public class DataColumn : ComponentBase public bool Sortable { get; set; } = true; [Parameter] - public int SortIndex - { - get => _sortIndex ?? -1; - set => SetInitialValue(ref _sortIndex, value); - } + public int SortIndex { get; set; } = -1; [Parameter] - public bool SortDescending - { - get => _sortDescending ?? false; - set => SetInitialValue(ref _sortDescending, value); - } + public bool SortDescending { get; set; } [Parameter] @@ -80,6 +74,11 @@ public bool SortDescending public RenderFragment FooterTemplate { get; set; } + internal int CurrentSortIndex { get; set; } = -1; + + internal bool CurrentSortDescending { get; set; } + + protected override void OnInitialized() { if (Grid == null) @@ -88,27 +87,13 @@ protected override void OnInitialized() if (Property == null) throw new InvalidOperationException("DataColumn Property parameter is required"); + CurrentSortIndex = SortIndex; + CurrentSortDescending = SortDescending; + // register with parent grid Grid.AddColumn(this); } - protected void OnChange() - { - InvokeAsync(StateHasChanged); - Grid?.RefreshAsync(); - } - - // parameter properties with internal changes can only be set once - protected void SetInitialValue(ref T field, T value) - { - if (field != null) - return; - - field = value; - OnChange(); - } - - internal string HeaderTitle() { if (!string.IsNullOrEmpty(Title)) @@ -146,8 +131,8 @@ internal string CellValue(TItem data) internal void UpdateSort(int index, bool descending) { - _sortIndex = index; - _sortDescending = descending; + CurrentSortIndex = index; + CurrentSortDescending = descending; } private string PropertyName() @@ -186,5 +171,23 @@ private string ToTitle(string value) return spacedName.ToString(); } + + internal Dictionary ComputeAttributes(TItem data) + { + var attributes = new Dictionary(); + if (CellAttributes != null) + { + var computed = CellAttributes(data); + if (computed != null) + foreach (var attribute in computed) + attributes[attribute.Key] = attribute.Value; + } + + if (UnmatchedAttributes != null) + foreach (var attribute in UnmatchedAttributes) + attributes[attribute.Key] = attribute.Value; + + return attributes; + } } } diff --git a/src/LoreSoft.Blazor.Controls/DataGrid.razor b/src/LoreSoft.Blazor.Controls/DataGrid.razor index 80f677d1..b37dd057 100644 --- a/src/LoreSoft.Blazor.Controls/DataGrid.razor +++ b/src/LoreSoft.Blazor.Controls/DataGrid.razor @@ -17,21 +17,21 @@ @if (DetailTemplate != null) { - + } @if (Selectable) { - + } @foreach (var column in VisibleColumns) { if (string.IsNullOrEmpty(column.Width)) { - + } else { - + } } @@ -46,7 +46,10 @@ {
- +
} @@ -105,7 +108,7 @@ @foreach (var column in VisibleColumns) { - + } @@ -173,7 +176,7 @@ { @if (LoadingTemplate == null) { - + } else { @@ -196,15 +199,18 @@ @column.HeaderTitle() } - @if (column.Sortable && column.SortIndex >= 0) + @if (column.Sortable && column.CurrentSortIndex >= 0) { - + } }; protected RenderFragment RowFragment => item => __builder => { - + @if (DetailTemplate != null) { @@ -217,13 +223,19 @@ {
- +
} @foreach (var column in VisibleColumns) { - + @if (column.Template != null) { @column.Template(item) diff --git a/src/LoreSoft.Blazor.Controls/DataGrid.razor.cs b/src/LoreSoft.Blazor.Controls/DataGrid.razor.cs index 58c083e2..158c9b63 100644 --- a/src/LoreSoft.Blazor.Controls/DataGrid.razor.cs +++ b/src/LoreSoft.Blazor.Controls/DataGrid.razor.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; + using Microsoft.AspNetCore.Components; namespace LoreSoft.Blazor.Controls @@ -38,6 +40,8 @@ public partial class DataGrid : DataComponentBase [Parameter] public Func RowStyle { get; set; } + [Parameter] + public Func> RowAttributes { get; set; } [Parameter] public IEnumerable SelectedItems { get; set; } = new List(); @@ -64,7 +68,7 @@ public async Task SortByAsync(DataColumn column) if (column == null || !Sortable || !column.Sortable) return; - var descending = column.SortIndex >= 0 && !column.SortDescending; + var descending = column.CurrentSortIndex >= 0 && !column.CurrentSortDescending; Columns.ForEach(c => c.UpdateSort(-1, false)); @@ -177,9 +181,9 @@ internal void AddColumn(DataColumn column) protected override DataRequest CreateDataRequest(CancellationToken cancellationToken) { var sorts = Columns - .Where(c => c.SortIndex >= 0) - .OrderBy(c => c.SortIndex) - .Select(c => new DataSort(c.Name, c.SortDescending)) + .Where(c => c.CurrentSortIndex >= 0) + .OrderBy(c => c.CurrentSortIndex) + .Select(c => new DataSort(c.Name, c.CurrentSortDescending)) .ToArray(); return new DataRequest(Pager.Page, Pager.PageSize, sorts, cancellationToken); @@ -194,7 +198,7 @@ protected override IQueryable SortData(IQueryable queryable, DataR var sorted = Columns .Where(c => columns.Contains(c.Name)) - .OrderBy(c => c.SortIndex) + .OrderBy(c => c.CurrentSortIndex) .ToList(); if (sorted.Count == 0) @@ -203,7 +207,7 @@ protected override IQueryable SortData(IQueryable queryable, DataR var queue = new Queue>(sorted); var column = queue.Dequeue(); - var orderedQueryable = column.SortDescending + var orderedQueryable = column.CurrentSortDescending ? queryable.OrderByDescending(column.Property) : queryable.OrderBy(column.Property); @@ -211,7 +215,7 @@ protected override IQueryable SortData(IQueryable queryable, DataR { column = queue.Dequeue(); - orderedQueryable = column.SortDescending + orderedQueryable = column.CurrentSortDescending ? orderedQueryable.ThenByDescending(column.Property) : orderedQueryable.ThenBy(column.Property); } @@ -220,4 +224,4 @@ protected override IQueryable SortData(IQueryable queryable, DataR } } -} +} \ No newline at end of file