diff --git a/BlazorAppTest/Pages/HxListLayoutTest.razor b/BlazorAppTest/Pages/HxListLayoutTest.razor index 0a9b11ed..def32f46 100644 --- a/BlazorAppTest/Pages/HxListLayoutTest.razor +++ b/BlazorAppTest/Pages/HxListLayoutTest.razor @@ -2,34 +2,34 @@

HxListLayout

- - - - - - - - - - - + + + + + + + + - - - - - - + + + + + + - + - + diff --git a/BlazorAppTest/Pages/HxListLayoutTest.razor.cs b/BlazorAppTest/Pages/HxListLayoutTest.razor.cs index 33893051..3dd404ff 100644 --- a/BlazorAppTest/Pages/HxListLayoutTest.razor.cs +++ b/BlazorAppTest/Pages/HxListLayoutTest.razor.cs @@ -13,9 +13,9 @@ public partial class HxListLayoutTest private readonly IEnumerable> namedViews = new List>() { - new NamedView("Minimum = 1", () => new FilterModelDto { MinimumItemId = 1 }), - new NamedView("Minimum = 2", () => new FilterModelDto { MinimumItemId = 2 }), - new NamedView("Minimum = 3", () => new FilterModelDto { MinimumItemId = 3 }) + new NamedView("Minimum ID = 1", () => new FilterModelDto { MinimumItemId = 1 }), + new NamedView("Minimum ID = 2", () => new FilterModelDto { MinimumItemId = 2 }), + new NamedView("Minimum ID = 3", () => new FilterModelDto { MinimumItemId = 3 }) }; private Task> LoadDataItems(GridDataProviderRequest request) @@ -48,15 +48,8 @@ private Task> LoadDataItems(GridDataProvider }); } - private async Task HandleFilterModelChanged(FilterModelDto newFilterModel) + private async Task RefreshDataAsync() { - filterModel = newFilterModel; - await gridComponent.RefreshDataAsync(); - } - - protected async Task NamedViewSelected(NamedView namedView) - { - filterModel = namedView.Filter(); await gridComponent.RefreshDataAsync(); } diff --git a/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor b/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor index 8e15805f..24107c5c 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor +++ b/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor @@ -5,35 +5,50 @@
- @if (NamedViewsTemplate != null) - { -
- + } + else if (TitleTemplate != null) + { +
@TitleTemplate
+ } + else if (!String.IsNullOrEmpty(Title)) + { +
@Title
+ } @if (SearchTemplate != null) { @SearchTemplate @@ -56,12 +71,12 @@ + Id="@filterFormId" + TModel="TFilterModel" + Model="FilterModel" + ModelChanged="HandleFilterFormModelChanged" + Context="filterContext" + OnChipsUpdated="HandleChipUpdated"> @FilterTemplate(filterContext) diff --git a/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.cs index 45ee3197..62d6d4cf 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Layouts/HxListLayout.razor.cs @@ -3,7 +3,7 @@ namespace Havit.Blazor.Components.Web.Bootstrap; /// -/// Data presentation component composed of for data, for manual filtering, and for pre-defined filters.
+/// Data presentation component composed of for data, for manual filtering, and named-views for pre-defined filters.
/// Full documentation and demos: https://havit.blazor.eu/components/HxListLayout ///
/// @@ -28,11 +28,49 @@ public partial class HxListLayout /// protected virtual ListLayoutSettings GetSettings() => this.Settings; + /// + /// Title of the component. + /// If is true and is not null, the component's title displays the name of the currently selected Named View. + /// [Parameter] public string Title { get; set; } + /// + /// Title of the component (in form of RenderFragment). + /// If is true and is not null, the component's title displays the name of the currently selected Named View. + /// [Parameter] public RenderFragment TitleTemplate { get; set; } - [Parameter] public RenderFragment NamedViewsTemplate { get; set; } + /// + /// Represents the collection of Named Views available for selection. + /// Each Named View defines a pre-set filter configuration that can be applied to the data. + /// + /// + /// Named Views provide a convenient way for users to quickly apply commonly used filters to the data set. + /// Ensure that each Named View in the collection has a unique name which accurately describes its filter criteria. + /// + [Parameter] public IEnumerable> NamedViews { get; set; } + + /// + /// Selected named view (highlighted in the list with .active CSS class). + /// + [Parameter] public NamedView SelectedNamedView { get; set; } + [Parameter] public EventCallback> SelectedNamedViewChanged { get; set; } + /// + /// Triggers the event. Allows interception of the event in derived components. + /// + protected virtual Task InvokeSelectedNamedViewChangedAsync(NamedView itemSelected) => SelectedNamedViewChanged.InvokeAsync(itemSelected); + + /// + /// Indicates whether the name of the selected Named View () is automatically used as title. + /// If true, the component's title changes to match the name of the currently selected Named View. + /// Useful for dynamic title updates based on user selections from predefined views. + /// The default value is true. + /// + /// + /// This update occurs upon the selection of a new Named View. It allows the Title to reflect the + /// current data filtering context provided by the Named Views, enhancing user understanding of the active filter. + /// + [Parameter] public bool TitleFromNamedView { get; set; } = true; [Parameter] public RenderFragment SearchTemplate { get; set; } @@ -116,4 +154,17 @@ private async Task HandleFilterFormModelChanged(TFilterModel newFilterModel) await InvokeFilterModelChangedAsync(newFilterModel); await filterOffcanvasComponent.HideAsync(); } + + private async Task HandleNamedViewClickAsync(NamedView namedView) + { + SelectedNamedView = namedView; + await InvokeSelectedNamedViewChangedAsync(namedView); + + TFilterModel newFilterModel = namedView.FilterModelFactory(); + if (newFilterModel != null) + { + FilterModel = newFilterModel; + await InvokeFilterModelChangedAsync(newFilterModel); + } + } } diff --git a/Havit.Blazor.Components.Web.Bootstrap/NamedViews/HxNamedViewList.razor b/Havit.Blazor.Components.Web.Bootstrap/NamedViews/HxNamedViewList.razor deleted file mode 100644 index e643cc10..00000000 --- a/Havit.Blazor.Components.Web.Bootstrap/NamedViews/HxNamedViewList.razor +++ /dev/null @@ -1,12 +0,0 @@ -@namespace Havit.Blazor.Components.Web.Bootstrap -@typeparam TFilterModel - -@if ((NamedViews != null) && NamedViews.Any()) -{ - -} \ No newline at end of file diff --git a/Havit.Blazor.Components.Web.Bootstrap/NamedViews/HxNamedViewList.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/NamedViews/HxNamedViewList.razor.cs deleted file mode 100644 index 99c3bc81..00000000 --- a/Havit.Blazor.Components.Web.Bootstrap/NamedViews/HxNamedViewList.razor.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Havit.Blazor.Components.Web.Bootstrap; - -/// -/// List of named views for .
-/// Full documentation and demos: https://havit.blazor.eu/components/HxNamedViewList -///
- -public partial class HxNamedViewList -{ - [Parameter] public IEnumerable> NamedViews { get; set; } - - [Parameter] public TFilterModel FilterModel { get; set; } - - [Parameter] public EventCallback FilterModelChanged { get; set; } - /// - /// Triggers the event. Allows interception of the event in derived components. - /// - protected virtual Task InvokeFilterModelChangedAsync(TFilterModel newFilterModel) => FilterModelChanged.InvokeAsync(newFilterModel); - - [Parameter] public EventCallback> OnNamedViewSelected { get; set; } - /// - /// Triggers the event. Allows interception of the event in derived components. - /// - protected virtual Task InvokeOnNamedViewSelectedAsync(NamedView namedViewSelected) => OnNamedViewSelected.InvokeAsync(namedViewSelected); - - protected async Task HandleNamedViewClick(NamedView namedView) - { - TFilterModel newFilter = namedView.Filter(); - if (newFilter != null) - { - FilterModel = newFilter; // BEWARE, the filter has to be cloned - await InvokeFilterModelChangedAsync(newFilter); - } - - await InvokeOnNamedViewSelectedAsync(namedView); - } -} diff --git a/Havit.Blazor.Components.Web.Bootstrap/NamedViews/NamedView.cs b/Havit.Blazor.Components.Web.Bootstrap/NamedViews/NamedView.cs index 2159de42..4b7e27fd 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/NamedViews/NamedView.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/NamedViews/NamedView.cs @@ -1,24 +1,28 @@ namespace Havit.Blazor.Components.Web.Bootstrap; +/// +/// Represents a named view for . +/// public class NamedView { + /// + /// Name of the view. Used as a label in the list. Can be used as a title for the . + /// public string Name { get; } - public Func Filter { get; } + /// + /// Creates new filter model for the view. + /// + public Func FilterModelFactory { get; } - public NamedView(string name) : this(name, () => default) - { - // NOOP - } - - public NamedView(string name, TFilterModel filter) : this(name, () => filter) - { - // NOOP - } - - public NamedView(string name, Func filterFunc) + /// + /// Creates a new instance of which uses a factory to build a filter model. + /// + /// Name of the view. + /// Function which builds a new filter model to be applied when the view is selected. + public NamedView(string name, Func filterModelFactory) { Name = name; - Filter = filterFunc; + FilterModelFactory = filterModelFactory; } } diff --git a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor index 8b0afadd..6140f05e 100644 --- a/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor +++ b/Havit.Blazor.Documentation/Pages/Components/HxListLayoutDoc/HxListLayout_Demo_NamedViews.razor @@ -1,16 +1,13 @@ - - - - - - - +@using Havit.Linq + + @@ -41,19 +38,18 @@ + + @code { [Inject] protected NavigationManager NavigationManager { get; set; } private EditableCultureInfo currentItem; private FilterModelDto filterModel = new FilterModelDto(); private HxGrid gridComponent; + private NamedView selectedNamedView; + private bool titleFromNamedView = true; - private readonly IEnumerable> namedViews = new List>() - { - new NamedView("Minimum = 1", () => new FilterModelDto { MinimumLCID = 1 } ), - new NamedView("Minimum = 50", () => new FilterModelDto { MinimumLCID = 50 }), - new NamedView("Minimum = 100", () => new FilterModelDto { MinimumLCID = 100 }) - }; + private IEnumerable> namedViews; private List localEditableCultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures).Select(c => new EditableCultureInfo() { @@ -63,21 +59,31 @@ EnglishName = c.EnglishName }).ToList(); - private Task> LoadDataItems(GridDataProviderRequest request) + protected override void OnInitialized() { - IEnumerable result = localEditableCultureInfos.Where(i => i.LCID >= filterModel.MinimumLCID).ToList(); + namedViews = new List>() + { + new NamedView("Default view", () => new FilterModelDto()), // resets the filter + new NamedView("Minimum = 1", () => filterModel with { MinimumLCID = 1 } ), // keep filter presets not affected by the view + new NamedView("Minimum = 50", () => filterModel with { MinimumLCID = 50 }), + new NamedView("Minimum = 100", () => filterModel with { MinimumLCID = 100 }) + }; - return Task.FromResult(request.ApplyTo(result)); + selectedNamedView = namedViews.First(); // set first view selected on initial load } - private async Task RefreshDataAsync() + private Task> LoadDataItems(GridDataProviderRequest request) { - await gridComponent.RefreshDataAsync(); + IEnumerable result = localEditableCultureInfos + .WhereIf(filterModel.MinimumLCID.HasValue, i => i.LCID >= filterModel.MinimumLCID) + .WhereIf(filterModel.MaximumLCID.HasValue, i => i.LCID <= filterModel.MaximumLCID) + .ToList(); + + return Task.FromResult(request.ApplyTo(result)); } - protected async Task NamedViewSelected(NamedView namedView) + private async Task RefreshDataAsync() { - filterModel = namedView.Filter(); await gridComponent.RefreshDataAsync(); } @@ -102,7 +108,8 @@ public record FilterModelDto { - public int MinimumLCID { get; set; } + public int? MinimumLCID { get; set; } + public int? MaximumLCID { get; set; } } private record EditableCultureInfo diff --git a/Havit.Blazor.Documentation/Pages/Components/HxNamedViewListDoc/HxNamedViewList_Documentation.razor b/Havit.Blazor.Documentation/Pages/Components/HxNamedViewListDoc/HxNamedViewList_Documentation.razor deleted file mode 100644 index edf1ffa2..00000000 --- a/Havit.Blazor.Documentation/Pages/Components/HxNamedViewListDoc/HxNamedViewList_Documentation.razor +++ /dev/null @@ -1,6 +0,0 @@ -@attribute [Route("/components/" + nameof(HxNamedViewList))] - - - - Use HxNamedViewList inside of HxListLayout. - \ No newline at end of file diff --git a/Havit.Blazor.Documentation/Shared/Sidebar.razor b/Havit.Blazor.Documentation/Shared/Sidebar.razor index 9c1df282..f2d5ca21 100644 --- a/Havit.Blazor.Documentation/Shared/Sidebar.razor +++ b/Havit.Blazor.Documentation/Shared/Sidebar.razor @@ -170,7 +170,6 @@ - )}")" Text="@(nameof(HxNamedViewList))" /> diff --git a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml index 3ced733e..264816d4 100644 --- a/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml +++ b/Havit.Blazor.Documentation/XmlDoc/Havit.Blazor.Components.Web.Bootstrap.xml @@ -6864,7 +6864,7 @@ - Data presentation component composed of for data, for manual filtering, and for pre-defined filters.
+ Data presentation component composed of for data, for manual filtering, and named-views for pre-defined filters.
Full documentation and demos: https://havit.blazor.eu/components/HxListLayout
@@ -6888,6 +6888,50 @@ Similar to , enables defining wider in component descendants (by returning a derived settings class).
+ + + Title of the component. + If is true and is not null, the component's title displays the name of the currently selected Named View. + + + + + Title of the component (in form of RenderFragment). + If is true and is not null, the component's title displays the name of the currently selected Named View. + + + + + Represents the collection of Named Views available for selection. + Each Named View defines a pre-set filter configuration that can be applied to the data. + + + Named Views provide a convenient way for users to quickly apply commonly used filters to the data set. + Ensure that each Named View in the collection has a unique name which accurately describes its filter criteria. + + + + + Selected named view (highlighted in the list with .active CSS class). + + + + + Triggers the event. Allows interception of the event in derived components. + + + + + Indicates whether the name of the selected Named View () is automatically used as title. + If true, the component's title changes to match the name of the currently selected Named View. + Useful for dynamic title updates based on user selections from predefined views. + The default value is true. + + + This update occurs upon the selection of a new Named View. It allows the Title to reflect the + current data filtering context provided by the Named Views, enhancing user understanding of the active filter. + + Triggers the event. Allows interception of the event in derived components. @@ -7719,21 +7763,27 @@ Extra large. Modal max-width: 1140px. - + + + Represents a named view for . + + + - List of named views for .
- Full documentation and demos: https://havit.blazor.eu/components/HxNamedViewList + Name of the view. Used as a label in the list. Can be used as a title for the .
- + - Triggers the event. Allows interception of the event in derived components. + Creates new filter model for the view. - + - Triggers the event. Allows interception of the event in derived components. + Creates a new instance of which uses a factory to build a filter model. + Name of the view. + Function which builds a new filter model to be applied when the view is selected.