Skip to content

Commit

Permalink
#791 FocusAsync() not working for indirect input-components
Browse files Browse the repository at this point in the history
  • Loading branch information
hakenr committed Apr 18, 2024
1 parent 941562e commit 2b825ed
Show file tree
Hide file tree
Showing 15 changed files with 280 additions and 130 deletions.
6 changes: 6 additions & 0 deletions BlazorAppTest/BlazorAppTest.csproj
Expand Up @@ -28,4 +28,10 @@
</Compile>
</ItemGroup>

<ItemGroup>
<Content Update="Pages\HxMultiSelect_Issue791_Test.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>

</Project>
50 changes: 50 additions & 0 deletions BlazorAppTest/Pages/HxMultiSelect_Issue791_Test.razor
@@ -0,0 +1,50 @@
@page "/HxMultiSelect_Issue791_Test"
@using System.Globalization

<h1>HxMultiSelect</h1>


<EditForm Model="@model">
<HxMultiSelect @ref="_component"
TItem="CultureInfo"
TValue="string"
Label="Cultures"
EmptyText="-- choose here --"
TextSelector="@(item => item.EnglishName)"
ValueSelector="@(item => item.EnglishName)"
Data="@data"
@bind-Value="@model.CultureInfos"
NullDataText="Loading languages..."
InputSize="InputSize.Small" />
</EditForm>

<p>Selected values: @String.Join(", ", model.CultureInfos ?? Enumerable.Empty<string>())</p>

@code
{
private HxMultiSelect<string, CultureInfo> _component;
private Model model = new Model();
private List<CultureInfo> data;

protected override async Task OnParametersSetAsync()
{
await base.OnParametersSetAsync();
await Task.Delay(3000);

data = CultureInfo.GetCultures(CultureTypes.SpecificCultures)
.OrderBy(item => item.EnglishName)
.Take(100)
.OrderByDescending(i => i.ToString()) // sorting test
.ToList();
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
await _component.FocusAsync();
}

private class Model
{
public List<string> CultureInfos { get; set; }
}
}
73 changes: 73 additions & 0 deletions BlazorAppTest/Pages/HxSearchBox_Issue791_Test.razor
@@ -0,0 +1,73 @@
@page "/HxSearchBox_Issue791_Test"

<HxSearchBox @ref="_component"
DataProvider="ProvideSearchResults"
Label="Search"
ItemTitleSelector="(i) => i.Title"
ItemSubtitleSelector="(i) => i.Subtitle"
ItemIconSelector="(i) => i.Icon"
TItem="SearchBoxItem">
<DefaultContentTemplate>
<div class="small py-2 px-3 text-muted">Search for Mouse, Table or Door...</div>
</DefaultContentTemplate>
</HxSearchBox>

@code {
private HxSearchBox<SearchBoxItem> _component;

List<SearchBoxItem> Data { get; set; } = new()
{
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed },
new() { Title = "Table", Subtitle = "$5000", Icon = BootstrapIcon.Table },
new() { Title = "Mouse", Subtitle = "$40", Icon = BootstrapIcon.Mouse },
new() { Title = "Door", Subtitle = "$100", Icon = BootstrapIcon.DoorClosed }
};

Task<SearchBoxDataProviderResult<SearchBoxItem>> ProvideSearchResults(SearchBoxDataProviderRequest request)
{
SearchBoxDataProviderResult<SearchBoxItem> result = new()
{
Data = Data.Where(i => i.Title.Contains(request.UserInput, StringComparison.OrdinalIgnoreCase)).ToArray()
};

return Task.FromResult(result);
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
await _component.FocusAsync();
}

class SearchBoxItem
{
public string Title { get; set; }
public string Subtitle { get; set; }
public BootstrapIcon Icon { get; set; }
}
}
Expand Up @@ -199,7 +199,7 @@ public override async ValueTask FocusAsync()
{
if (_hxAutosuggestInternalComponent == null)
{
throw new InvalidOperationException($"Cannot focus {GetType()}. The method must be called after first render.");
throw new InvalidOperationException($"Unable to focus {nameof(HxAutosuggest)}. The component reference is not available. You are most likely calling the method too early. The first render must complete before calling this method.");
}

await _hxAutosuggestInternalComponent.FocusAsync();
Expand Down
2 changes: 1 addition & 1 deletion Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputBase.cs
Expand Up @@ -433,7 +433,7 @@ public virtual async ValueTask FocusAsync()
{
if (EqualityComparer<ElementReference>.Default.Equals(InputElement, default))
{
throw new InvalidOperationException($"Unable to focus {GetType().Name}, {nameof(InputElement)} reference not available (You are most likely calling the method too early, first render has to complete first.)");
throw new InvalidOperationException($"Unable to focus {GetType().Name}, {nameof(InputElement)} reference not available. You are most likely calling the method too early. The first render must complete before calling this method.");
}
await InputElement.FocusAsync();
}
Expand Down
2 changes: 1 addition & 1 deletion Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputDate.cs
Expand Up @@ -207,7 +207,7 @@ public override ValueTask FocusAsync()
{
if (_hxInputDateInternalComponent is null)
{
throw new InvalidOperationException($"Unable to focus {nameof(HxInputDate)}, component reference not available (You are most likely calling the method too early, first render has to complete first.)");
throw new InvalidOperationException($"Unable to focus {nameof(HxInputDate)}. The component reference is not available. You are most likely calling the method too early. The first render must complete before calling this method.");
}

return _hxInputDateInternalComponent.FocusAsync();
Expand Down
Expand Up @@ -176,7 +176,7 @@ public override ValueTask FocusAsync()
{
if (_hxInputDateRangeInternalComponent is null)
{
throw new InvalidOperationException($"Unable to focus {nameof(HxInputDateRange)}, component reference not available (You are most likely calling the method too early, first render has to complete first.)");
throw new InvalidOperationException($"Unable to focus {nameof(HxInputDateRange)}. The component reference is not available. You are most likely calling the method too early. The first render must complete before calling this method.");
}

return _hxInputDateRangeInternalComponent.FocusAsync();
Expand Down
Expand Up @@ -196,7 +196,7 @@ public override async ValueTask FocusAsync()
{
if (_hxMultiSelectInternalComponent == null)
{
throw new InvalidOperationException($"Cannot focus {GetType()}. The method must be called after first render.");
throw new InvalidOperationException($"Unable to focus {nameof(HxMultiSelect)}. The component reference is not available. You are most likely calling the method too early. The first render must complete before calling this method.");
}

await _hxMultiSelectInternalComponent.FocusAsync();
Expand Down

0 comments on commit 2b825ed

Please sign in to comment.