diff --git a/src/BlazorTable.Sample.Server/wwwroot/css/site.css b/src/BlazorTable.Sample.Server/wwwroot/css/site.css index c15c2e15..1b535477 100644 --- a/src/BlazorTable.Sample.Server/wwwroot/css/site.css +++ b/src/BlazorTable.Sample.Server/wwwroot/css/site.css @@ -48,6 +48,7 @@ app { .sidebar { background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); + overflow: auto; } .sidebar .top-row { diff --git a/src/BlazorTable.Sample.Shared/BlazorTable.Sample.Shared.csproj b/src/BlazorTable.Sample.Shared/BlazorTable.Sample.Shared.csproj index 5154481d..66cac8e6 100644 --- a/src/BlazorTable.Sample.Shared/BlazorTable.Sample.Shared.csproj +++ b/src/BlazorTable.Sample.Shared/BlazorTable.Sample.Shared.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/src/BlazorTable.Sample.Shared/NavMenu.razor b/src/BlazorTable.Sample.Shared/NavMenu.razor index 2a81e847..75ebebd4 100644 --- a/src/BlazorTable.Sample.Shared/NavMenu.razor +++ b/src/BlazorTable.Sample.Shared/NavMenu.razor @@ -67,11 +67,21 @@ Dynamic Columns + + diff --git a/src/BlazorTable.Sample.Shared/Pages/Detail.razor b/src/BlazorTable.Sample.Shared/Pages/Detail.razor index 409aac7c..02055e07 100644 --- a/src/BlazorTable.Sample.Shared/Pages/Detail.razor +++ b/src/BlazorTable.Sample.Shared/Pages/Detail.razor @@ -6,7 +6,28 @@

The DetailTemplate can be used to display additional details below an item.


- +
+
+ + +
+
+
+
Row Number:
+
+ +
+
+ + +
+
+
+@if (errorMessage != "") +{ + +} +
@@ -46,8 +67,14 @@ [Inject] private HttpClient Http { get; set; } + private ITable table; + private PersonData[] data; + private int rowNumber; + + private string errorMessage = ""; + protected override async Task OnInitializedAsync() { data = await Http.GetFromJsonAsync("sample-data/MOCK_DATA.json"); @@ -71,4 +98,17 @@ MasterCard = 1, Visa = 2 } + + private void Try(Action action) + { + try + { + errorMessage = ""; + action(); + } + catch (Exception e) + { + errorMessage = e.Message; + } + } } diff --git a/src/BlazorTable.Sample.Shared/Pages/RowTemplate.razor b/src/BlazorTable.Sample.Shared/Pages/RowTemplate.razor new file mode 100644 index 00000000..32ee5058 --- /dev/null +++ b/src/BlazorTable.Sample.Shared/Pages/RowTemplate.razor @@ -0,0 +1,80 @@ +@page "/CustomRow" +@inject HttpClient Http +@using BlazorTable +@using System.ComponentModel + +

Row Template - Custom Row

+ +

+ +

Use

+ +
+ + + + + + + + + + + + + + + + + + + + + +
+
Custom Row
+
+ +@code +{ + [Inject] + private HttpClient httpClient { get; set; } + + private ITable table; + + private PersonData[] data; + + private int i = 0; + + protected override async Task OnInitializedAsync() + { + data = await httpClient.GetFromJsonAsync("sample-data/MOCK_DATA.json"); + } + + public class PersonData + { + public int? id { get; set; } + public string full_name { get; set; } + public string email { get; set; } + public bool? paid { get; set; } + public decimal? price { get; set; } + public CreditCard? cc_type { get; set; } + public DateTime? created_date { get; set; } + } + + public enum CreditCard + { + none = 0, + [Description("MasterCard")] + MasterCard = 1, + Visa = 2 + } +} diff --git a/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor b/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor new file mode 100644 index 00000000..929403e9 --- /dev/null +++ b/src/BlazorTable.Sample.Shared/Pages/ServerSideData.razor @@ -0,0 +1,100 @@ +@page "/ServerSideData" +@inject HttpClient Http +@using BlazorTable +@using BlazorTable.Interfaces +@using BlazorTable.Components.ServerSide + +

Server side data

+ + + + + + + + + + + + + + + +
+ +@code +{ + [Inject] + private HttpClient httpClient { get; set; } + + public class PersonData + { + public int? id { get; set; } + public string full_name { get; set; } + public string email { get; set; } + public bool? paid { get; set; } + public decimal? price { get; set; } + public DateTime? created_date { get; set; } + } + + private IDataLoader _loader; + + private IEnumerable data; + + protected override async Task OnInitializedAsync() + { + _loader = new PersonDataLoader(httpClient); + data = (await _loader.LoadDataAsync(null)).Records; + } + + public class PersonDataLoader : IDataLoader + { + private readonly HttpClient _client; + public PersonDataLoader(HttpClient client) + { + _client = client; + } + public async Task> LoadDataAsync(FilterData parameters) + { + + var data = await _client.GetFromJsonAsync("sample-data/MOCK_DATA.json"); + IQueryable query = data.AsQueryable(); + if (parameters?.Query != null) + { + query = query.Where( + x => x.email.ToLowerInvariant().Contains(parameters.Query.ToLowerInvariant()) || + x.full_name.ToLowerInvariant().Contains(parameters.Query.ToLowerInvariant())); + } + if (parameters?.OrderBy != null) + { + var orderBy = parameters.OrderBy.Split(" "); + if (orderBy.Length == 2) + { + var isSortDescending = orderBy[1] == "desc"; + var prop = typeof(PersonData).GetProperty(orderBy[0]); + query = isSortDescending ? query.OrderByDescending(x => prop.GetValue(x, null)) + : query.OrderBy(x => prop.GetValue(x, null)); + } + } + var results = parameters?.Top.HasValue ?? false ? + query.Skip(parameters.Skip.GetValueOrDefault()) + .Take(parameters.Top.Value).ToArray() : + query.ToArray(); + + return new PaginationResult + { + Records = results, + Skip = parameters?.Skip ?? 0, + Total = query.ToList().Count, + Top = parameters?.Top ?? 0 + }; + } + } + +} diff --git a/src/BlazorTable.Sample.Shared/Pages/ToggleColumnVisibility.razor b/src/BlazorTable.Sample.Shared/Pages/ToggleColumnVisibility.razor index 3d7bf8ff..c3a8c8dc 100644 --- a/src/BlazorTable.Sample.Shared/Pages/ToggleColumnVisibility.razor +++ b/src/BlazorTable.Sample.Shared/Pages/ToggleColumnVisibility.razor @@ -5,9 +5,11 @@

Toggle Column Visibility

+

Users can change the visibility of a column if its "Hideable" attribute is set to true.

+ - +
@@ -35,10 +37,12 @@
@code -{ +{ [Inject] private HttpClient httpClient { get; set; } + private ITable table; + private PersonData[] data; private bool showSearchBar; @@ -46,6 +50,13 @@ protected override async Task OnInitializedAsync() { data = await httpClient.GetFromJsonAsync("sample-data/MOCK_DATA.json"); + + Random random = new Random(123); + + foreach (IColumn column in table.Columns) + { + column.Visible = random.Next(2) == 1 ? true : false; // column visibility + } } public class PersonData diff --git a/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css b/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css index 7164cb2a..aa02184c 100644 --- a/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css +++ b/src/BlazorTable.Sample.Wasm/wwwroot/css/site.css @@ -48,6 +48,7 @@ app { .sidebar { background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); + overflow: auto; } .sidebar .top-row { diff --git a/src/BlazorTable.Tests/BlazorTable.Tests.csproj b/src/BlazorTable.Tests/BlazorTable.Tests.csproj index e8ae8d44..e387b7eb 100644 --- a/src/BlazorTable.Tests/BlazorTable.Tests.csproj +++ b/src/BlazorTable.Tests/BlazorTable.Tests.csproj @@ -7,16 +7,16 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/BlazorTable/BlazorTable.csproj b/src/BlazorTable/BlazorTable.csproj index 6600f78c..8cb7c277 100644 --- a/src/BlazorTable/BlazorTable.csproj +++ b/src/BlazorTable/BlazorTable.csproj @@ -27,11 +27,11 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -45,7 +45,7 @@ - + True True Localization.resx @@ -53,7 +53,7 @@ - + ResXFileCodeGenerator Localization.Designer.cs diff --git a/src/BlazorTable/Components/Column.razor.cs b/src/BlazorTable/Components/Column.razor.cs index bd0257f6..dec41914 100644 --- a/src/BlazorTable/Components/Column.razor.cs +++ b/src/BlazorTable/Components/Column.razor.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Linq; using System.Linq.Expressions; +using System.Threading.Tasks; namespace BlazorTable { @@ -225,7 +226,7 @@ public void ToggleFilter() /// /// Sort by this column /// - public void SortBy() + public async Task SortByAsync() { if (Sortable) { @@ -238,7 +239,7 @@ public void SortBy() SortColumn = true; - Table.Update(); + await Table.UpdateAsync().ConfigureAwait(false); } } diff --git a/src/BlazorTable/Components/CustomRow.razor b/src/BlazorTable/Components/CustomRow.razor new file mode 100644 index 00000000..f1c72614 --- /dev/null +++ b/src/BlazorTable/Components/CustomRow.razor @@ -0,0 +1,2 @@ +@namespace BlazorTable +@typeparam TableItem diff --git a/src/BlazorTable/Components/CustomRow.razor.cs b/src/BlazorTable/Components/CustomRow.razor.cs new file mode 100644 index 00000000..bc2778c9 --- /dev/null +++ b/src/BlazorTable/Components/CustomRow.razor.cs @@ -0,0 +1,38 @@ +using Microsoft.AspNetCore.Components; +using System; + +namespace BlazorTable +{ + /// + /// A custom row template + /// + /// + public partial class CustomRow : ComponentBase + { + /// + /// Parent Table + /// + [CascadingParameter(Name = "Table")] + public ITable Table { get; set; } + + /// + /// Function that defines if the custom row is active for the TableItem inserted as parameter + /// + [Parameter] + public Func IsActiveForItem { get; set; } + + /// + /// Content to show + /// + [Parameter] + public RenderFragment ChildContent { get; set; } + + /// + /// When initialized, add custom row to table + /// + protected override void OnInitialized() + { + Table.AddCustomRow(this); + } + } +} diff --git a/src/BlazorTable/Components/FilterManager.razor b/src/BlazorTable/Components/FilterManager.razor index a698ca80..bc98129e 100644 --- a/src/BlazorTable/Components/FilterManager.razor +++ b/src/BlazorTable/Components/FilterManager.razor @@ -1,6 +1,5 @@ @namespace BlazorTable @typeparam TableItem -@inject Microsoft.Extensions.Localization.IStringLocalizer Localization @ChildContent @@ -9,6 +8,6 @@
- - + +
diff --git a/src/BlazorTable/Components/FilterManager.razor.cs b/src/BlazorTable/Components/FilterManager.razor.cs index 46ce23ff..bb1f8285 100644 --- a/src/BlazorTable/Components/FilterManager.razor.cs +++ b/src/BlazorTable/Components/FilterManager.razor.cs @@ -1,4 +1,6 @@ -using Microsoft.AspNetCore.Components; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; namespace BlazorTable @@ -14,15 +16,19 @@ public partial class FilterManager [Inject] public ILogger> Logger { get; set; } - private void ApplyFilter() + [Inject] + IStringLocalizer Localization { get; set; } + + private async Task ApplyFilterAsync() + { Column.ToggleFilter(); if (Column.FilterControl != null) { Column.Filter = Column.FilterControl.GetFilter(); - Column.Table.Update(); - Column.Table.FirstPage(); + await Column.Table.UpdateAsync().ConfigureAwait(false); + await Column.Table.FirstPageAsync().ConfigureAwait(false); } else { @@ -30,14 +36,14 @@ private void ApplyFilter() } } - private void ClearFilter() + private async Task ClearFilterAsync() { Column.ToggleFilter(); if (Column.Filter != null) { Column.Filter = null; - Column.Table.Update(); + await Column.Table.UpdateAsync().ConfigureAwait(false); } } } diff --git a/src/BlazorTable/Components/Pager.razor b/src/BlazorTable/Components/Pager.razor index 6947d9b7..8cd3332e 100644 --- a/src/BlazorTable/Components/Pager.razor +++ b/src/BlazorTable/Components/Pager.razor @@ -1,5 +1,4 @@ @namespace BlazorTable -@inject Microsoft.Extensions.Localization.IStringLocalizer Localization @if (AlwaysShow || (Table.TotalPages > 1)) { @@ -8,7 +7,7 @@ @if (ShowPageSizes) {
  • - @foreach (int option in PageSizes) { @@ -18,13 +17,13 @@ } @if (ShowPageNumber) { -
  • +
  • @(Table.PageNumber + 1)/@(Table.TotalPages)
  • } @if (ShowTotalCount) { -
  • +
  • @Table.TotalCount
  • } @@ -35,16 +34,16 @@ } -
  • +
  • @Localization["PagerFirst"]
  • -
  • +
  • @Localization["PagerPrevious"]
  • -
  • +
  • @Localization["PagerNext"]
  • -
  • +
  • @Localization["PagerLast"]
  • diff --git a/src/BlazorTable/Components/Pager.razor.cs b/src/BlazorTable/Components/Pager.razor.cs index 15d0c296..d51bee2b 100644 --- a/src/BlazorTable/Components/Pager.razor.cs +++ b/src/BlazorTable/Components/Pager.razor.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; using System.Collections.Generic; -using System.Threading; +using System.Threading.Tasks; namespace BlazorTable { @@ -42,11 +43,14 @@ public partial class Pager [Parameter] public bool ShowPageSizes { get; set; } - private void SetPageSize(ChangeEventArgs args) + [Inject] + IStringLocalizer Localization { get; set; } + + private async Task SetPageSizeAsync(ChangeEventArgs args) { if (int.TryParse(args.Value.ToString(), out int result)) { - Table.SetPageSize(result); + await Table.SetPageSizeAsync(result).ConfigureAwait(false); } } } diff --git a/src/BlazorTable/Components/ServerSide/FilterData.cs b/src/BlazorTable/Components/ServerSide/FilterData.cs new file mode 100644 index 00000000..b2dbf743 --- /dev/null +++ b/src/BlazorTable/Components/ServerSide/FilterData.cs @@ -0,0 +1,14 @@ +namespace BlazorTable.Components.ServerSide +{ + public class FilterData + { + public string OrderBy { get; set; } + + public string Query { get; set; } + + public int? Top { get; set; } + + public int? Skip { get; set; } + } + +} diff --git a/src/BlazorTable/Components/ServerSide/PaginationResult.cs b/src/BlazorTable/Components/ServerSide/PaginationResult.cs new file mode 100644 index 00000000..6e42c251 --- /dev/null +++ b/src/BlazorTable/Components/ServerSide/PaginationResult.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BlazorTable.Components.ServerSide +{ + public class PaginationResult + { + public int Top { get; set; } + + public int Skip { get; set; } + + public int? Total { get; set; } + + public IEnumerable Records { get; set; } + } +} diff --git a/src/BlazorTable/Components/Table.razor b/src/BlazorTable/Components/Table.razor index 91a4fcbe..f9411af2 100644 --- a/src/BlazorTable/Components/Table.razor +++ b/src/BlazorTable/Components/Table.razor @@ -1,6 +1,12 @@ @namespace BlazorTable @typeparam TableItem -@inject Microsoft.Extensions.Localization.IStringLocalizer Localization + +@if (ShowChildContentAtTop) +{ + + @ChildContent + +} @if (Columns.Any()) { @@ -15,7 +21,7 @@ @if (ShowSearchBar) { - + } @if (Columns.Exists(column => !column.Visible)) { @@ -24,7 +30,7 @@ - +

    Column Visibility

    @@ -42,10 +48,11 @@ - + - + + }