Skip to content

Commit 61098b6

Browse files
Make InputBase use EventCallback for ValueChanged (#7915)
* Make InputBase use EventCallback for ValueChanged ... so that the host component gets re-rendered automatically after each value change (like when binding to DOM elements). * Improve E2E test code ... so that the host component gets re-rendered automatically after each value change (like when binding to DOM elements).
1 parent 3c558b2 commit 61098b6

File tree

4 files changed

+26
-3
lines changed

4 files changed

+26
-3
lines changed

src/Components/Components/src/Forms/InputComponents/InputBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public abstract class InputBase<T> : ComponentBase
4242
/// <summary>
4343
/// Gets or sets a callback that updates the bound value.
4444
/// </summary>
45-
[Parameter] Action<T> ValueChanged { get; set; }
45+
[Parameter] EventCallback<T> ValueChanged { get; set; }
4646

4747
/// <summary>
4848
/// Gets or sets an expression that identifies the bound value.
@@ -71,7 +71,7 @@ protected T CurrentValue
7171
if (hasChanged)
7272
{
7373
Value = value;
74-
ValueChanged?.Invoke(value);
74+
_ = ValueChanged.InvokeAsync(value);
7575
EditContext.NotifyFieldChanged(FieldIdentifier);
7676
}
7777
}

src/Components/Components/test/Forms/InputBaseTest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,8 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
459459
{
460460
childBuilder.OpenComponent<TComponent>(0);
461461
childBuilder.AddAttribute(0, "Value", Value);
462-
childBuilder.AddAttribute(1, "ValueChanged", ValueChanged);
462+
childBuilder.AddAttribute(1, "ValueChanged",
463+
EventCallback.Factory.Create(this, ValueChanged));
463464
childBuilder.AddAttribute(2, "ValueExpression", ValueExpression);
464465
childBuilder.AddAttribute(3, nameof(Id), Id);
465466
childBuilder.AddAttribute(4, nameof(Class), Class);

src/Components/test/E2ETest/Tests/FormsTest.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,27 @@ public void ValidationMessageDisplaysMessagesForField()
316316
WaitAssert.Empty(emailMessagesAccessor);
317317
}
318318

319+
[Fact]
320+
public void InputComponentsCauseContainerToRerenderOnChange()
321+
{
322+
var appElement = MountTestComponent<TypicalValidationComponent>();
323+
var ticketClassInput = new SelectElement(appElement.FindElement(By.ClassName("ticket-class")).FindElement(By.TagName("select")));
324+
var selectedTicketClassDisplay = appElement.FindElement(By.Id("selected-ticket-class"));
325+
var messagesAccessor = CreateValidationMessagesAccessor(appElement);
326+
327+
// Shows initial state
328+
WaitAssert.Equal("Economy", () => selectedTicketClassDisplay.Text);
329+
330+
// Refreshes on edit
331+
ticketClassInput.SelectByValue("Premium");
332+
WaitAssert.Equal("Premium", () => selectedTicketClassDisplay.Text);
333+
334+
// Leaves previous value unchanged if new entry is unparseable
335+
ticketClassInput.SelectByText("(select)");
336+
WaitAssert.Equal(new[] { "The TicketClass field is not valid." }, messagesAccessor);
337+
WaitAssert.Equal("Premium", () => selectedTicketClassDisplay.Text);
338+
}
339+
319340
private Func<string[]> CreateValidationMessagesAccessor(IWebElement appElement)
320341
{
321342
return () => appElement.FindElements(By.ClassName("validation-message"))

src/Components/test/testassets/BasicTestApp/FormsTest/TypicalValidationComponent.cshtml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<option value="@TicketClass.Premium">Premium class</option>
3535
<option value="@TicketClass.First">First class</option>
3636
</InputSelect>
37+
<span id="selected-ticket-class">@person.TicketClass</span>
3738
</p>
3839
<p class="accepts-terms">
3940
Accepts terms: <InputCheckbox bind-Value="@person.AcceptsTerms" />

0 commit comments

Comments
 (0)