Skip to content

Commit

Permalink
[FluentSlider] [FluentNumberField] Fix #2948 (#3077)
Browse files Browse the repository at this point in the history
* fixes issue where slider value from being set directly multiple times consecutively

* debounce the call to the javascript used to update the slider thumb.

* allows FluentNumberField to be set programmatically

* adds IAsyncDisposable to FluentNumberField

* Eases BUnit constraints

* fixes flickering when typing in value

* use javascript MuatationObserver instead

* fixes failing FluentNumberFieldTests

---------

Co-authored-by: Vincent Baaij <[email protected]>
  • Loading branch information
oneolddev and vnbaaij authored Dec 27, 2024
1 parent 75b8f5f commit 1c28dbb
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 19 deletions.
23 changes: 21 additions & 2 deletions src/Core/Components/NumberField/FluentNumberField.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.FluentUI.AspNetCore.Components;

public partial class FluentNumberField<TValue> : FluentInputBase<TValue>
public partial class FluentNumberField<TValue> : FluentInputBase<TValue>, IAsyncDisposable
{
private const string JAVASCRIPT_FILE = "./_content/Microsoft.FluentUI.AspNetCore.Components/Components/TextField/FluentTextField.razor.js";

Expand Down Expand Up @@ -166,12 +166,31 @@ protected override async Task OnAfterRenderAsync(bool firstRender)

if (firstRender)
{
Module ??= await JSRuntime.InvokeAsync<IJSObjectReference>("import", JAVASCRIPT_FILE.FormatCollocatedUrl(LibraryConfiguration));
await Module.InvokeVoidAsync("ensureCurrentValueMatch", Element);

if (AutoComplete != null && !string.IsNullOrEmpty(Id))
{
Module ??= await JSRuntime.InvokeAsync<IJSObjectReference>("import", JAVASCRIPT_FILE.FormatCollocatedUrl(LibraryConfiguration));
await Module.InvokeVoidAsync("setControlAttribute", Id, "autocomplete", AutoComplete);
}

}
}

public async ValueTask DisposeAsync()
{
try
{
if (Module is not null)
{
await Module.DisposeAsync();
}
}
catch (Exception ex) when (ex is JSDisconnectedException ||
ex is OperationCanceledException)
{
// The JSRuntime side may routinely be gone already if the reason we're disposing is that
// the client disconnected. This is not an error.
}
}
}
27 changes: 11 additions & 16 deletions src/Core/Components/Slider/FluentSlider.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.AspNetCore.Components;
using Microsoft.FluentUI.AspNetCore.Components.Extensions;
using Microsoft.FluentUI.AspNetCore.Components.Utilities;
using Microsoft.FluentUI.AspNetCore.Components.Utilities.InternalDebounce;
using Microsoft.JSInterop;

namespace Microsoft.FluentUI.AspNetCore.Components;
Expand All @@ -27,7 +28,11 @@ public partial class FluentSlider<TValue> : FluentInputBase<TValue>, IAsyncDispo
private TValue? max;
private TValue? min;
private bool updateSliderThumb = false;
private bool userChangedValue = false;
private DebounceAction Debounce { get; init; }
public FluentSlider()
{
Debounce = new DebounceAction();
}

/// <summary>
/// Gets or sets the slider's minimal value.
Expand Down Expand Up @@ -71,14 +76,7 @@ public override TValue? Value
if (base.Value != value)
{
base.Value = value;
if (userChangedValue)
{
userChangedValue = false;
}
else
{
updateSliderThumb = true;
}
updateSliderThumb = true;
}
}
}
Expand Down Expand Up @@ -120,18 +118,15 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
updateSliderThumb = false;
if (Module is not null)
{
await Module!.InvokeVoidAsync("updateSlider", Element);
Debounce.Run(100, async () =>
{
await Module!.InvokeVoidAsync("updateSlider", Element);
});
}
}
}
}

protected override Task ChangeHandlerAsync(ChangeEventArgs e)
{
userChangedValue = true;
return base.ChangeHandlerAsync(e);
}

protected override string? ClassValue
{
get
Expand Down
19 changes: 18 additions & 1 deletion src/Core/Components/TextField/FluentTextField.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,21 @@ export function setDataList(id, datalistid) {
shadowRoot.removeChild(shadowDataList);
}
shadowRoot.appendChild(dataList);
}
}

export function ensureCurrentValueMatch(ref) {
if (ref !== undefined && ref != null) {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === "attributes") {
ref.value = mutation.target.getAttribute("value");
}
});
});
observer.observe(ref, {
attributes: true,
attributeFilter: ["value"],
});
}
}

1 change: 1 addition & 0 deletions tests/Core/NumberField/FluentNumberFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class FluentNumberFieldTests : TestBase
public FluentNumberFieldTests()
{
TestContext.Services.AddSingleton(LibraryConfiguration);
TestContext.JSInterop.Mode = JSRuntimeMode.Loose;
}

[Fact]
Expand Down
1 change: 1 addition & 0 deletions tests/Core/Wizard/FluentWizardTests.razor
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
public FluentWizardTests()
{
this.Services.AddSingleton(LibraryConfiguration);
JSInterop.Mode = JSRuntimeMode.Loose;
}

[Fact]
Expand Down

0 comments on commit 1c28dbb

Please sign in to comment.