Files
jsmr/JSMR.UI.Blazor/Shared/SearchPageBase.cs

122 lines
3.0 KiB
C#

using JSMR.Application.Common.Search;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.JSInterop;
namespace JSMR.UI.Blazor.Shared;
public abstract class SearchPageBase<TState, TItem> : ComponentBase, IAsyncDisposable
where TState : notnull
{
[Inject]
protected NavigationManager Nav { get; set; } = default!;
[Inject]
protected IJSRuntime JS { get; set; } = default!;
protected TState State { get; private set; } = default!;
protected SearchResult<TItem>? Result { get; private set; }
protected bool IsLoading { get; private set; }
private bool _suppressNextLocation;
private bool _isAlive = true;
private CancellationTokenSource _cancellationTokenSource = new();
protected override async Task OnInitializedAsync()
{
Nav.LocationChanged += OnLocationChanged;
State = ParseStateFromUri(Nav.Uri);
await RunSearchAsync();
}
protected async Task UpdateAsync(TState next)
{
if (Equals(next, State))
return;
State = next;
NavigateToState(next);
_ = RunSearchAsync();
}
private void NavigateToState(TState next)
{
string uri = BuildUri(next);
_suppressNextLocation = true;
Nav.NavigateTo(uri);
}
private async void OnLocationChanged(object? sender, LocationChangedEventArgs e)
{
if (_suppressNextLocation)
{
_suppressNextLocation = false;
return;
}
if (!_isAlive)
return;
if (!IsThisPage(e.Location))
return;
TState next = ParseStateFromUri(e.Location);
if (Equals(next, State))
return;
State = next;
await InvokeAsync(StateHasChanged);
_ = RunSearchAsync();
}
private async Task RunSearchAsync()
{
await JS.InvokeVoidAsync("pageHelpers.scrollToTop");
try
{
IsLoading = true;
//StateHasChanged();
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new();
Result = await ExecuteSearchAsync(State, _cancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
}
finally
{
if (_isAlive)
{
IsLoading = false;
await InvokeAsync(StateHasChanged);
}
}
}
protected abstract TState ParseStateFromUri(string absoluteUri);
protected abstract string BuildUri(TState state);
protected abstract bool IsThisPage(string absoluteUri);
protected abstract Task<SearchResult<TItem>> ExecuteSearchAsync(TState state, CancellationToken cancellationToken);
public async ValueTask DisposeAsync()
{
_isAlive = false;
Nav.LocationChanged -= OnLocationChanged;
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
GC.SuppressFinalize(this);
await Task.CompletedTask;
}
}