Skip to content

Commit 70dedc6

Browse files
committed
Support updating/changing the binding prefix
1 parent 308609d commit 70dedc6

12 files changed

+110
-15
lines changed

src/Components/Components/test/CascadingParameterStateTest.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ class FormParametersComponent : TestComponentBase
468468

469469
class FormParametersComponentWithName : TestComponentBase
470470
{
471-
[SupplyParameterFromForm(Name = "some-name")] public string FormParameter { get; set; }
471+
[SupplyParameterFromForm(Handler = "some-name")] public string FormParameter { get; set; }
472472
}
473473

474474
class ComponentWithNoCascadingParams : TestComponentBase
@@ -554,4 +554,10 @@ public sealed class SupplyParameterFromFormAttribute : CascadingParameterAttribu
554554
/// the form data and decide whether or not the value needs to be bound.
555555
/// </summary>
556556
public override string Name { get; set; }
557+
558+
/// <summary>
559+
/// Gets or sets the name for the handler. The name is used to match
560+
/// the form data and decide whether or not the value needs to be bound.
561+
/// </summary>
562+
public string Handler { get; set; }
557563
}

src/Components/Web/src/Binding/CascadingFormModelBindingProvider.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ protected internal override bool CanSupplyValue(ModelBindingContext? bindingCont
4545
Debug.Assert(bindingContext != null);
4646
var (formName, valueType) = GetFormNameAndValueType(bindingContext, parameterInfo);
4747

48-
var parameterName = parameterInfo.Attribute.Name;
49-
50-
Action<string, FormattableString, string?> errorHandler = string.IsNullOrEmpty(parameterName) ?
48+
var parameterName = parameterInfo.Attribute.Name ?? parameterInfo.PropertyName;
49+
var handler = ((SupplyParameterFromFormAttribute)parameterInfo.Attribute).Handler;
50+
Action<string, FormattableString, string?> errorHandler = string.IsNullOrEmpty(handler) ?
5151
bindingContext.AddError :
52-
(name, message, value) => bindingContext.AddError(parameterName, name, message, value);
52+
(name, message, value) => bindingContext.AddError(formName, parameterName, message, value);
5353

54-
var context = new FormValueSupplierContext(formName!, valueType, parameterInfo.PropertyName)
54+
var context = new FormValueSupplierContext(formName!, valueType, parameterName)
5555
{
5656
OnError = errorHandler,
5757
MapErrorToContainer = bindingContext.AttachParentValue
@@ -65,7 +65,7 @@ protected internal override bool CanSupplyValue(ModelBindingContext? bindingCont
6565
private static (string FormName, Type ValueType) GetFormNameAndValueType(ModelBindingContext? bindingContext, in CascadingParameterInfo parameterInfo)
6666
{
6767
var valueType = parameterInfo.PropertyType;
68-
var valueName = parameterInfo.Attribute.Name;
68+
var valueName = ((SupplyParameterFromFormAttribute)parameterInfo.Attribute).Handler;
6969
var formName = string.IsNullOrEmpty(valueName) ?
7070
(bindingContext?.Name) :
7171
ModelBindingContext.Combine(bindingContext, valueName);

src/Components/Web/src/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Microsoft.AspNetCore.Components.HtmlRendering.Infrastructure.StaticHtmlRenderer.
2929
Microsoft.AspNetCore.Components.HtmlRendering.Infrastructure.StaticHtmlRenderer.StaticHtmlRenderer(System.IServiceProvider! serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory! loggerFactory) -> void
3030
Microsoft.AspNetCore.Components.RenderTree.WebRenderer.WaitUntilAttachedAsync() -> System.Threading.Tasks.Task!
3131
Microsoft.AspNetCore.Components.SupplyParameterFromFormAttribute
32+
Microsoft.AspNetCore.Components.SupplyParameterFromFormAttribute.Handler.get -> string?
33+
Microsoft.AspNetCore.Components.SupplyParameterFromFormAttribute.Handler.set -> void
3234
Microsoft.AspNetCore.Components.SupplyParameterFromFormAttribute.SupplyParameterFromFormAttribute() -> void
3335
Microsoft.AspNetCore.Components.Web.AutoRenderMode
3436
Microsoft.AspNetCore.Components.Web.AutoRenderMode.AutoRenderMode() -> void

src/Components/Web/src/SupplyParameterFromFormAttribute.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,15 @@ namespace Microsoft.AspNetCore.Components;
1111
public sealed class SupplyParameterFromFormAttribute : CascadingParameterAttributeBase
1212
{
1313
/// <summary>
14-
/// Gets or sets the name for the parameter. The name is used to match
15-
/// the form data and decide whether or not the value needs to be bound.
14+
/// Gets or sets the name for the parameter. The name is used to determine
15+
/// the prefix to use to match the form data and decide whether or not the
16+
/// value needs to be bound.
1617
/// </summary>
1718
public override string? Name { get; set; }
19+
20+
/// <summary>
21+
/// Gets or sets the name for the handler. The name is used to match
22+
/// the form data and decide whether or not the value needs to be bound.
23+
/// </summary>
24+
public string? Handler { get; set; }
1825
}

src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,32 @@ public void CanBindMultipleParametersToTheDefaultForm(bool suppressEnhancedNavig
154154
Browser.Exists(By.Id("OtherParameterValue")).Text.Contains("True");
155155
}
156156

157+
[Theory]
158+
[InlineData(true)]
159+
[InlineData(false)]
160+
public void CanChangeFormParameterNames(bool suppressEnhancedNavigation)
161+
{
162+
var dispatchToForm = new DispatchToForm(this)
163+
{
164+
Url = "forms/default-form-bound-multiple-primitive-parameters-changed-names",
165+
FormCssSelector = "form",
166+
ExpectedActionValue = null,
167+
UpdateFormAction = () =>
168+
{
169+
Browser.Exists(By.CssSelector("input[name=UpdatedParameter]")).Clear();
170+
Browser.Exists(By.CssSelector("input[name=UpdatedParameter]")).SendKeys("10");
171+
172+
Browser.Exists(By.CssSelector("input[name=UpdatedOtherParameter]")).Clear();
173+
Browser.Exists(By.CssSelector("input[name=UpdatedOtherParameter]")).SendKeys("true");
174+
},
175+
SuppressEnhancedNavigation = suppressEnhancedNavigation,
176+
};
177+
DispatchToFormCore(dispatchToForm);
178+
179+
Browser.Exists(By.Id("ParameterValue")).Text.Contains("10");
180+
Browser.Exists(By.Id("OtherParameterValue")).Text.Contains("True");
181+
}
182+
157183
[Theory]
158184
[InlineData(true)]
159185
[InlineData(false)]

src/Components/test/testassets/Components.TestServer/RazorComponents/Components/ComponentWithFormBoundParameter.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313
@code{
1414
bool _submitted = false;
1515

16-
[SupplyParameterFromForm(Name = "named-form-handler")] public string Parameter { get; set; } = "";
16+
[SupplyParameterFromForm(Handler = "named-form-handler")] public string Parameter { get; set; } = "";
1717
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
@page "/forms/default-form-bound-multiple-primitive-parameters-changed-names"
2+
@using Microsoft.AspNetCore.Components.Forms
3+
4+
<h2>Default form with bound parameter</h2>
5+
6+
<ActionForm OnSubmit="() => _submitted = true">
7+
<input type="text" name="UpdatedParameter" value="@(_attemptedParameterValue ?? Parameter.ToString())" />
8+
<input type="text" name="UpdatedOtherParameter" value="@(_attemptedOtherValue ?? OtherParameter.ToString())" />
9+
<AntiforgeryToken />
10+
<input id="send" type="submit" value="Send" />
11+
</ActionForm>
12+
13+
@if (_submitted)
14+
{
15+
if (_errors.Count == 0)
16+
{
17+
<p id="ParameterValue">Your number is @Parameter!</p>
18+
<p id="OtherParameterValue">Your other value is @OtherParameter!</p>
19+
}
20+
else
21+
{
22+
<p>There were errors:</p>
23+
<ul id="errors">
24+
@foreach (var error in _errors)
25+
{
26+
<li>@error</li>
27+
}
28+
</ul>
29+
}
30+
}
31+
@code {
32+
bool _submitted = false;
33+
string _attemptedParameterValue = null;
34+
string _attemptedOtherValue = null;
35+
36+
IList<FormattableString> _errors;
37+
38+
[SupplyParameterFromForm(Name = "UpdatedParameter")] public int Parameter { get; set; } = 0;
39+
[SupplyParameterFromForm(Name = "UpdatedOtherParameter")] public bool OtherParameter { get; set; } = false;
40+
41+
[CascadingParameter] public ModelBindingContext Context { get; set; }
42+
43+
protected override void OnInitialized()
44+
{
45+
_errors = (Context.GetErrors("UpdatedParameter")?.ErrorMessages ?? Array.Empty<FormattableString>())
46+
.Concat(Context.GetErrors("UpdatedOtherParameter")?.ErrorMessages ?? Array.Empty<FormattableString>()).ToList();
47+
48+
if (_errors.Count > 0)
49+
{
50+
_attemptedParameterValue = Context.GetAttemptedValue("UpdatedParameter");
51+
_attemptedOtherValue = Context.GetAttemptedValue("UpdatedOtherParameter");
52+
}
53+
}
54+
}

src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormThatBindsGuid.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
string _attemptedValue = null;
3232
IReadOnlyList<FormattableString> _errors;
3333

34-
[SupplyParameterFromForm(Name = "bind-guid")] public Guid Id { get; set; } = Guid.NewGuid();
34+
[SupplyParameterFromForm(Handler = "bind-guid")] public Guid Id { get; set; } = Guid.NewGuid();
3535

3636
[CascadingParameter] public ModelBindingContext Context { get; set; }
3737

src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/FormThatBindsInteger.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
string _attemptedValue = null;
3232
IReadOnlyList<FormattableString> _errors;
3333

34-
[SupplyParameterFromForm(Name = "bind-integer")] public int Id { get; set; } = 0;
34+
[SupplyParameterFromForm(Handler = "bind-integer")] public int Id { get; set; } = 0;
3535

3636
[CascadingParameter] public ModelBindingContext Context { get; set; }
3737

src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/NamedFormBoundParameter.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@
1616
@code{
1717
bool _submitted = false;
1818

19-
[SupplyParameterFromForm(Name = "named-form-handler")] public string Parameter { get; set; } = "";
19+
[SupplyParameterFromForm(Handler = "named-form-handler")] public string Parameter { get; set; } = "";
2020
}

src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/NamedFormBoundPrimitiveParameter.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
string _attemptedValue = null;
3434
IReadOnlyList<FormattableString> _errors;
3535

36-
[SupplyParameterFromForm(Name = "named-form-handler")] public int Parameter { get; set; } = 0;
36+
[SupplyParameterFromForm(Handler = "named-form-handler")] public int Parameter { get; set; } = 0;
3737

3838
[CascadingParameter] public ModelBindingContext Context { get; set; }
3939

src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/NamedFormBoundPrimitiveParameterValidatorIntegration.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
@code {
2121
bool _submitted = false;
2222

23-
[SupplyParameterFromForm(Name = "named-form-handler")] public DataModel Model { get; set; }
23+
[SupplyParameterFromForm(Handler = "named-form-handler")] public DataModel Model { get; set; }
2424

2525
[CascadingParameter] public ModelBindingContext Context { get; set; }
2626

0 commit comments

Comments
 (0)