Mgbbs/hidden for checkbox render mode (#13014)

* Added CheckBoxHiddenInputRenderMode to HtmlHelperOptions, ViewContext, and html/tag helpers

Fixes #12833
This commit is contained in:
mgbbs 2019-08-26 18:00:00 -05:00 committed by Pranav K
parent a88180472d
commit 90e89e9708
8 changed files with 406 additions and 22 deletions

View File

@ -309,29 +309,32 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
"checkbox")); "checkbox"));
} }
// hiddenForCheckboxTag always rendered after the returned element if (ViewContext.CheckBoxHiddenInputRenderMode != CheckBoxHiddenInputRenderMode.None)
var hiddenForCheckboxTag = Generator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, For.Name);
if (hiddenForCheckboxTag != null)
{ {
var renderingMode = // hiddenForCheckboxTag always rendered after the returned element
output.TagMode == TagMode.SelfClosing ? TagRenderMode.SelfClosing : TagRenderMode.StartTag; var hiddenForCheckboxTag = Generator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, For.Name);
hiddenForCheckboxTag.TagRenderMode = renderingMode; if (hiddenForCheckboxTag != null)
if (!hiddenForCheckboxTag.Attributes.ContainsKey("name") &&
!string.IsNullOrEmpty(Name))
{ {
// The checkbox and hidden elements should have the same name attribute value. Attributes will var renderingMode =
// match if both are present because both have a generated value. Reach here in the special case output.TagMode == TagMode.SelfClosing ? TagRenderMode.SelfClosing : TagRenderMode.StartTag;
// where user provided a non-empty fallback name. hiddenForCheckboxTag.TagRenderMode = renderingMode;
hiddenForCheckboxTag.MergeAttribute("name", Name); if (!hiddenForCheckboxTag.Attributes.ContainsKey("name") &&
} !string.IsNullOrEmpty(Name))
{
// The checkbox and hidden elements should have the same name attribute value. Attributes will
// match if both are present because both have a generated value. Reach here in the special case
// where user provided a non-empty fallback name.
hiddenForCheckboxTag.MergeAttribute("name", Name);
}
if (ViewContext.FormContext.CanRenderAtEndOfForm) if (ViewContext.CheckBoxHiddenInputRenderMode == CheckBoxHiddenInputRenderMode.EndOfForm && ViewContext.FormContext.CanRenderAtEndOfForm)
{ {
ViewContext.FormContext.EndOfFormContent.Add(hiddenForCheckboxTag); ViewContext.FormContext.EndOfFormContent.Add(hiddenForCheckboxTag);
} }
else else
{ {
output.PostElement.AppendHtml(hiddenForCheckboxTag); output.PostElement.AppendHtml(hiddenForCheckboxTag);
}
} }
} }

View File

@ -838,6 +838,243 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
Assert.Equal(expectedTagName, output.TagName); Assert.Equal(expectedTagName, output.TagName);
} }
[Fact]
public async Task ProcessAsync_GenerateCheckBox_WithHiddenInputRenderModeNone()
{
var propertyName = "-expression-";
var expectedTagName = "input";
var inputTypeName = "checkbox";
var expectedAttributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
{ "value", "true" },
};
var metadataProvider = new EmptyModelMetadataProvider();
var htmlGenerator = new TestableHtmlGenerator(metadataProvider);
var model = false;
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(bool), model);
var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer);
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
viewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.None;
var tagHelper = new InputTagHelper(htmlGenerator)
{
For = modelExpression,
InputTypeName = inputTypeName,
Name = propertyName,
ViewContext = viewContext,
};
var attributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
};
var context = new TagHelperContext(attributes, new Dictionary<object, object>(), "test");
var output = new TagHelperOutput(
expectedTagName,
new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(result: null))
{
TagMode = TagMode.SelfClosing,
};
// Act
await tagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal(expectedAttributes, output.Attributes);
Assert.False(output.IsContentModified);
Assert.Equal(expectedTagName, output.TagName);
Assert.False(viewContext.FormContext.HasEndOfFormContent);
Assert.True(string.IsNullOrEmpty(HtmlContentUtilities.HtmlContentToString(output.PostElement)));
}
[Fact]
public async Task ProcessAsync_GenerateCheckBox_WithHiddenInputRenderModeInline()
{
var propertyName = "-expression-";
var expectedTagName = "input";
var expectedPostElementContent = $"<input name=\"HtmlEncode[[{propertyName}]]\" " +
"type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" />";
var inputTypeName = "checkbox";
var expectedAttributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
{ "value", "true" },
};
var metadataProvider = new EmptyModelMetadataProvider();
var htmlGenerator = new TestableHtmlGenerator(metadataProvider);
var model = false;
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(bool), model);
var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer);
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
viewContext.FormContext.CanRenderAtEndOfForm = true;
viewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.Inline;
var tagHelper = new InputTagHelper(htmlGenerator)
{
For = modelExpression,
InputTypeName = inputTypeName,
Name = propertyName,
ViewContext = viewContext,
};
var attributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
};
var context = new TagHelperContext(attributes, new Dictionary<object, object>(), "test");
var output = new TagHelperOutput(
expectedTagName,
new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(result: null))
{
TagMode = TagMode.SelfClosing,
};
// Act
await tagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal(expectedAttributes, output.Attributes);
Assert.False(output.IsContentModified);
Assert.Equal(expectedTagName, output.TagName);
Assert.False(viewContext.FormContext.HasEndOfFormContent);
Assert.Equal(expectedPostElementContent, HtmlContentUtilities.HtmlContentToString(output.PostElement));
}
[Fact]
public async Task ProcessAsync_GenerateCheckBox_WithHiddenInputRenderModeEndOfForm()
{
var propertyName = "-expression-";
var expectedTagName = "input";
var expectedEndOfFormContent = $"<input name=\"HtmlEncode[[{propertyName}]]\" " +
"type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" />";
var inputTypeName = "checkbox";
var expectedAttributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
{ "value", "true" },
};
var metadataProvider = new EmptyModelMetadataProvider();
var htmlGenerator = new TestableHtmlGenerator(metadataProvider);
var model = false;
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(bool), model);
var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer);
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
viewContext.FormContext.CanRenderAtEndOfForm = true;
viewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.EndOfForm;
var tagHelper = new InputTagHelper(htmlGenerator)
{
For = modelExpression,
InputTypeName = inputTypeName,
Name = propertyName,
ViewContext = viewContext,
};
var attributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
};
var context = new TagHelperContext(attributes, new Dictionary<object, object>(), "test");
var output = new TagHelperOutput(
expectedTagName,
new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(result: null))
{
TagMode = TagMode.SelfClosing,
};
// Act
await tagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal(expectedAttributes, output.Attributes);
Assert.False(output.IsContentModified);
Assert.Equal(expectedTagName, output.TagName);
Assert.Equal(expectedEndOfFormContent, string.Join("", viewContext.FormContext.EndOfFormContent.Select(html => HtmlContentUtilities.HtmlContentToString(html))));
Assert.True(string.IsNullOrEmpty(HtmlContentUtilities.HtmlContentToString(output.PostElement)));
}
[Fact]
public async Task ProcessAsync_GenerateCheckBox_WithHiddenInputRenderModeEndOfForm_AndCanRenderAtEndOfFormNotSet()
{
var propertyName = "-expression-";
var expectedTagName = "input";
var expectedPostElementContent = $"<input name=\"HtmlEncode[[{propertyName}]]\" " +
"type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" />";
var inputTypeName = "checkbox";
var expectedAttributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
{ "value", "true" },
};
var metadataProvider = new EmptyModelMetadataProvider();
var htmlGenerator = new TestableHtmlGenerator(metadataProvider);
var model = false;
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(bool), model);
var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer);
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
viewContext.FormContext.CanRenderAtEndOfForm = false;
viewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.EndOfForm;
var tagHelper = new InputTagHelper(htmlGenerator)
{
For = modelExpression,
InputTypeName = inputTypeName,
Name = propertyName,
ViewContext = viewContext,
};
var attributes = new TagHelperAttributeList
{
{ "name", propertyName },
{ "type", inputTypeName },
};
var context = new TagHelperContext(attributes, new Dictionary<object, object>(), "test");
var output = new TagHelperOutput(
expectedTagName,
new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(result: null))
{
TagMode = TagMode.SelfClosing,
};
// Act
await tagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal(expectedAttributes, output.Attributes);
Assert.False(output.IsContentModified);
Assert.Equal(expectedTagName, output.TagName);
Assert.False(viewContext.FormContext.HasEndOfFormContent);
Assert.Equal(expectedPostElementContent, HtmlContentUtilities.HtmlContentToString(output.PostElement));
}
[Fact] [Fact]
public async Task ProcessAsync_CallsGenerateCheckBox_WithExpectedParameters() public async Task ProcessAsync_CallsGenerateCheckBox_WithExpectedParameters()
{ {

View File

@ -312,6 +312,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
} }
namespace Microsoft.AspNetCore.Mvc.Rendering namespace Microsoft.AspNetCore.Mvc.Rendering
{ {
public enum CheckBoxHiddenInputRenderMode
{
None = 0,
Inline = 1,
EndOfForm = 2,
}
public enum FormMethod public enum FormMethod
{ {
Get = 0, Get = 0,
@ -678,6 +684,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
public ViewContext() { } public ViewContext() { }
public ViewContext(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ViewEngines.IView view, Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary viewData, Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionary tempData, System.IO.TextWriter writer, Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelperOptions htmlHelperOptions) { } public ViewContext(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ViewEngines.IView view, Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary viewData, Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionary tempData, System.IO.TextWriter writer, Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelperOptions htmlHelperOptions) { }
public ViewContext(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext, Microsoft.AspNetCore.Mvc.ViewEngines.IView view, Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary viewData, System.IO.TextWriter writer) { } public ViewContext(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext, Microsoft.AspNetCore.Mvc.ViewEngines.IView view, Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary viewData, System.IO.TextWriter writer) { }
public Microsoft.AspNetCore.Mvc.Rendering.CheckBoxHiddenInputRenderMode CheckBoxHiddenInputRenderMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool ClientValidationEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public bool ClientValidationEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public string ExecutingFilePath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public string ExecutingFilePath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public virtual Microsoft.AspNetCore.Mvc.ViewFeatures.FormContext FormContext { get { throw null; } set { } } public virtual Microsoft.AspNetCore.Mvc.ViewFeatures.FormContext FormContext { get { throw null; } set { } }
@ -1062,6 +1069,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
public partial class HtmlHelperOptions public partial class HtmlHelperOptions
{ {
public HtmlHelperOptions() { } public HtmlHelperOptions() { }
public Microsoft.AspNetCore.Mvc.Rendering.CheckBoxHiddenInputRenderMode CheckBoxHiddenInputRenderMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool ClientValidationEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public bool ClientValidationEnabled { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public Microsoft.AspNetCore.Mvc.Rendering.Html5DateRenderingMode Html5DateRenderingMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public Microsoft.AspNetCore.Mvc.Rendering.Html5DateRenderingMode Html5DateRenderingMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public string IdAttributeDotReplacement { get { throw null; } set { } } public string IdAttributeDotReplacement { get { throw null; } set { } }

View File

@ -721,8 +721,18 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
isChecked, isChecked,
htmlAttributes); htmlAttributes);
if (checkbox == null)
{
return HtmlString.Empty;
}
if (ViewContext.CheckBoxHiddenInputRenderMode == CheckBoxHiddenInputRenderMode.None)
{
return checkbox;
}
var hiddenForCheckbox = _htmlGenerator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, expression); var hiddenForCheckbox = _htmlGenerator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, expression);
if (checkbox == null || hiddenForCheckbox == null) if (hiddenForCheckbox == null)
{ {
return HtmlString.Empty; return HtmlString.Empty;
} }
@ -736,7 +746,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
hiddenForCheckbox.MergeAttribute("name", name); hiddenForCheckbox.MergeAttribute("name", name);
} }
if (ViewContext.FormContext.CanRenderAtEndOfForm) if (ViewContext.CheckBoxHiddenInputRenderMode == CheckBoxHiddenInputRenderMode.EndOfForm && ViewContext.FormContext.CanRenderAtEndOfForm)
{ {
ViewContext.FormContext.EndOfFormContent.Add(hiddenForCheckbox); ViewContext.FormContext.EndOfFormContent.Add(hiddenForCheckbox);
return checkbox; return checkbox;

View File

@ -56,5 +56,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
/// <see cref="IHtmlHelper.ValidationSummary"/> and other overloads. /// <see cref="IHtmlHelper.ValidationSummary"/> and other overloads.
/// </summary> /// </summary>
public string ValidationSummaryMessageElement { get; set; } = "span"; public string ValidationSummaryMessageElement { get; set; } = "span";
/// <summary>
/// Gets or sets the way hidden inputs are rendered for checkbox tag helpers and html helpers.
/// </summary>
public CheckBoxHiddenInputRenderMode CheckBoxHiddenInputRenderMode { get; set; } = CheckBoxHiddenInputRenderMode.EndOfForm;
} }
} }

View File

@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Mvc.Rendering
{
/// <summary>
/// Controls the rendering of hidden input fields when using CheckBox tag helpers or html helpers.
/// </summary>
public enum CheckBoxHiddenInputRenderMode
{
/// <summary>
/// Hidden input fields will not be automatically rendered. If checkbox is not checked, no value will be posted.
/// </summary>
None = 0,
/// <summary>
/// Hidden input fields will be rendered inline with each checkbox. Use this for legacy ASP.NET MVC behavior.
/// </summary>
Inline = 1,
/// <summary>
/// Hidden input fields will be rendered for each checkbox at the bottom of the form element. This is the preferred render method and default MVC behavior.
/// If <see cref="Microsoft.AspNetCore.Mvc.ViewFeatures.FormContext.CanRenderAtEndOfForm"/> is <c>false</c>, will fall back on <see cref="Inline"/>.
/// </summary>
EndOfForm = 2
}
}

View File

@ -87,6 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
Html5DateRenderingMode = htmlHelperOptions.Html5DateRenderingMode; Html5DateRenderingMode = htmlHelperOptions.Html5DateRenderingMode;
ValidationSummaryMessageElement = htmlHelperOptions.ValidationSummaryMessageElement; ValidationSummaryMessageElement = htmlHelperOptions.ValidationSummaryMessageElement;
ValidationMessageElement = htmlHelperOptions.ValidationMessageElement; ValidationMessageElement = htmlHelperOptions.ValidationMessageElement;
CheckBoxHiddenInputRenderMode = htmlHelperOptions.CheckBoxHiddenInputRenderMode;
} }
/// <summary> /// <summary>
@ -129,6 +130,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
Html5DateRenderingMode = viewContext.Html5DateRenderingMode; Html5DateRenderingMode = viewContext.Html5DateRenderingMode;
ValidationSummaryMessageElement = viewContext.ValidationSummaryMessageElement; ValidationSummaryMessageElement = viewContext.ValidationSummaryMessageElement;
ValidationMessageElement = viewContext.ValidationMessageElement; ValidationMessageElement = viewContext.ValidationMessageElement;
CheckBoxHiddenInputRenderMode = viewContext.CheckBoxHiddenInputRenderMode;
ExecutingFilePath = viewContext.ExecutingFilePath; ExecutingFilePath = viewContext.ExecutingFilePath;
View = view; View = view;
@ -180,6 +182,11 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
/// </summary> /// </summary>
public string ValidationMessageElement { get; set; } public string ValidationMessageElement { get; set; }
/// <summary>
/// Gets or sets the way hidden inputs are rendered for checkbox tag helpers and html helpers.
/// </summary>
public CheckBoxHiddenInputRenderMode CheckBoxHiddenInputRenderMode { get; set; }
/// <summary> /// <summary>
/// Gets the dynamic view bag. /// Gets the dynamic view bag.
/// </summary> /// </summary>

View File

@ -169,6 +169,93 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
writer.ToString()); writer.ToString());
} }
[Fact]
public void CheckBox_WithHiddenInputRenderModeNone_DoesNotGenerateHiddenInput()
{
// Arrange
var requiredMessage = ValidationAttributeUtil.GetRequiredErrorMessage("Boolean");
var expected = @"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
$@"data-val-required=""HtmlEncode[[{requiredMessage}]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" " +
@"value=""HtmlEncode[[true]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.None;
// Act
var html = helper.CheckBox("Property1", isChecked: true, htmlAttributes: null);
// Assert
Assert.False(helper.ViewContext.FormContext.HasEndOfFormContent);
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(html));
}
[Fact]
public void CheckBox_WithHiddenInputRenderModeInline_GeneratesHiddenInput()
{
// Arrange
var requiredMessage = ValidationAttributeUtil.GetRequiredErrorMessage("Boolean");
var expected = @"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
$@"data-val-required=""HtmlEncode[[{requiredMessage}]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" " +
@"value=""HtmlEncode[[true]]"" /><input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.FormContext.CanRenderAtEndOfForm = true;
helper.ViewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.Inline;
// Act
var html = helper.CheckBox("Property1", isChecked: true, htmlAttributes: null);
// Assert
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(html));
}
[Fact]
public void CheckBox_WithHiddenInputRenderModeEndOfForm_GeneratesHiddenInput()
{
// Arrange
var requiredMessage = ValidationAttributeUtil.GetRequiredErrorMessage("Boolean");
var expected = @"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
$@"data-val-required=""HtmlEncode[[{requiredMessage}]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" " +
@"value=""HtmlEncode[[true]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.FormContext.CanRenderAtEndOfForm = true;
helper.ViewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.EndOfForm;
// Act
var html = helper.CheckBox("Property1", isChecked: true, htmlAttributes: null);
// Assert
Assert.True(helper.ViewContext.FormContext.HasEndOfFormContent);
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(html));
var writer = new StringWriter();
var hiddenTag = Assert.Single(helper.ViewContext.FormContext.EndOfFormContent);
hiddenTag.WriteTo(writer, new HtmlTestEncoder());
Assert.Equal("<input name=\"HtmlEncode[[Property1]]\" type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" />",
writer.ToString());
}
[Fact]
public void CheckBox_WithHiddenInputRenderModeEndOfForm_WithCanRenderAtEndOfFormNotSet_GeneratesHiddenInput()
{
// Arrange
var requiredMessage = ValidationAttributeUtil.GetRequiredErrorMessage("Boolean");
var expected = @"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
$@"data-val-required=""HtmlEncode[[{requiredMessage}]]"" id=""HtmlEncode[[Property1]]"" " +
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" " +
@"value=""HtmlEncode[[true]]"" /><input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />";
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewContext.FormContext.CanRenderAtEndOfForm = false;
helper.ViewContext.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.EndOfForm;
// Act
var html = helper.CheckBox("Property1", isChecked: true, htmlAttributes: null);
// Assert
Assert.False(helper.ViewContext.FormContext.HasEndOfFormContent);
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(html));
}
[Fact] [Fact]
public void CheckBoxUsesAttemptedValueFromModelState() public void CheckBoxUsesAttemptedValueFromModelState()
{ {