Provide selected values to `<option/>` tag helpers
- value may remain in the `FormContext` beyond `</select>` end tag but will be cleaned up at the `</form>` end tag of the containing `<form/>` element - `SelectTagHelper` called prior to helpers for contained `<option/>`s and not again later - adjust mock setups to handle new `GenerateSelect()` call - add assertions for expected `FormContext.FormData` entry nit: mention #1468 in a test comment
This commit is contained in:
parent
3d84b528e5
commit
30f25fec99
|
|
@ -18,6 +18,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
[ContentBehavior(ContentBehavior.Append)]
|
||||
public class SelectTagHelper : TagHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Key used for selected values in <see cref="FormContext.FormData"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Value for this dictionary entry will either be <c>null</c> (indicating no <see cref="SelectTagHelper"/> has
|
||||
/// executed within this <form/>) or an <see cref="ICollection{string}"/> instance. Elements of the
|
||||
/// collection are based on current <see cref="ViewDataDictionary.Model"/>.
|
||||
/// </remarks>
|
||||
public static readonly string SelectedValuesFormDataKey = nameof(SelectTagHelper) + "-SelectedValues";
|
||||
|
||||
// Protected to ensure subclasses are correctly activated. Internal for ease of use when testing.
|
||||
[Activate]
|
||||
protected internal IHtmlGenerator Generator { get; set; }
|
||||
|
|
@ -114,6 +124,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Ensure GenerateSelect() _never_ looks anything up in ViewData.
|
||||
var items = Items ?? Enumerable.Empty<SelectListItem>();
|
||||
|
||||
ICollection<string> selectedValues;
|
||||
var tagBuilder = Generator.GenerateSelect(
|
||||
ViewContext,
|
||||
For.Metadata,
|
||||
|
|
@ -121,13 +132,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
name: For.Name,
|
||||
selectList: items,
|
||||
allowMultiple: allowMultiple,
|
||||
htmlAttributes: null);
|
||||
htmlAttributes: null,
|
||||
selectedValues: out selectedValues);
|
||||
|
||||
if (tagBuilder != null)
|
||||
{
|
||||
output.SelfClosing = false;
|
||||
output.Merge(tagBuilder);
|
||||
}
|
||||
|
||||
// Whether or not (not being highly unlikely) we generate anything, could update contained <option/>
|
||||
// elements. Provide selected values for <option/> tag helpers. They'll run next.
|
||||
ViewContext.FormContext.FormData[SelectedValuesFormDataKey] = selectedValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
// Skip last two test cases because DefaultHtmlGenerator evaluates expression name against
|
||||
// ViewData, not using ModelMetadata.Model. ViewData.Eval() handles simple property paths and some
|
||||
// dictionary lookups, but not indexing into an array or list. Will file a follow-up bug on this...
|
||||
// dictionary lookups, but not indexing into an array or list. See #1468...
|
||||
////{ models, typeof(Model), () => models[1].Text,
|
||||
//// new NameAndId("[1].Text", "z1__Text"), outerSelected },
|
||||
////{ models, typeof(NestedModel), () => models[1].NestedModel.Text,
|
||||
|
|
@ -213,6 +213,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
Assert.Equal(expectedContent, output.Content);
|
||||
Assert.False(output.SelfClosing);
|
||||
Assert.Equal(expectedTagName, output.TagName);
|
||||
|
||||
Assert.NotNull(viewContext.FormContext?.FormData);
|
||||
var keyValuePair = Assert.Single(
|
||||
viewContext.FormContext.FormData,
|
||||
entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
|
||||
Assert.NotNull(keyValuePair.Value);
|
||||
var selectedValues = Assert.IsAssignableFrom<ICollection<string>>(keyValuePair.Value);
|
||||
Assert.InRange(selectedValues.Count, 0, 1);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -278,6 +286,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
Assert.Equal(expectedContent, output.Content);
|
||||
Assert.False(output.SelfClosing);
|
||||
Assert.Equal(expectedTagName, output.TagName);
|
||||
|
||||
Assert.NotNull(viewContext.FormContext?.FormData);
|
||||
var keyValuePair = Assert.Single(
|
||||
viewContext.FormContext.FormData,
|
||||
entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
|
||||
Assert.NotNull(keyValuePair.Value);
|
||||
var selectedValues = Assert.IsAssignableFrom<ICollection<string>>(keyValuePair.Value);
|
||||
Assert.InRange(selectedValues.Count, 0, 1);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -312,6 +328,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
var htmlGenerator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
|
||||
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);
|
||||
ICollection<string> selectedValues = new string[0];
|
||||
htmlGenerator
|
||||
.Setup(real => real.GenerateSelect(
|
||||
viewContext,
|
||||
|
|
@ -320,7 +337,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
propertyName, // name
|
||||
expectedItems,
|
||||
expectedAllowMultiple,
|
||||
null)) // htmlAttributes
|
||||
null, // htmlAttributes
|
||||
out selectedValues))
|
||||
.Returns((TagBuilder)null)
|
||||
.Verifiable();
|
||||
|
||||
|
|
@ -338,6 +356,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
// Assert
|
||||
htmlGenerator.Verify();
|
||||
|
||||
Assert.NotNull(viewContext.FormContext?.FormData);
|
||||
var keyValuePair = Assert.Single(
|
||||
viewContext.FormContext.FormData,
|
||||
entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
|
||||
Assert.Same(selectedValues, keyValuePair.Value);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -363,6 +387,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
var htmlGenerator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
|
||||
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);
|
||||
ICollection<string> selectedValues = new string[0];
|
||||
htmlGenerator
|
||||
.Setup(real => real.GenerateSelect(
|
||||
viewContext,
|
||||
|
|
@ -371,7 +396,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
propertyName, // name
|
||||
It.IsAny<IEnumerable<SelectListItem>>(),
|
||||
allowMultiple,
|
||||
null)) // htmlAttributes
|
||||
null, // htmlAttributes
|
||||
out selectedValues))
|
||||
.Returns((TagBuilder)null)
|
||||
.Verifiable();
|
||||
|
||||
|
|
@ -387,6 +413,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
// Assert
|
||||
htmlGenerator.Verify();
|
||||
|
||||
Assert.NotNull(viewContext.FormContext?.FormData);
|
||||
var keyValuePair = Assert.Single(
|
||||
viewContext.FormContext.FormData,
|
||||
entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
|
||||
Assert.Same(selectedValues, keyValuePair.Value);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
|
|||
Loading…
Reference in New Issue