Moving the order of generated hidden tags for checkbox to end of the form
- #2994 - Affects both HtmlHelper and TagHelper scenarios - Checkboxes not enclosed in a form will generate inline hidden tags - Added necessary properties to FormContext - Added some functional and unit tests
This commit is contained in:
parent
03625c38af
commit
d40e6612a4
|
|
@ -278,7 +278,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
if (hiddenForCheckboxTag != null)
|
||||
{
|
||||
hiddenForCheckboxTag.TagRenderMode = renderingMode;
|
||||
output.Content.Append(hiddenForCheckboxTag);
|
||||
|
||||
if (ViewContext.FormContext.CanRenderAtEndOfForm)
|
||||
{
|
||||
ViewContext.FormContext.EndOfFormContent.Add(hiddenForCheckboxTag);
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Content.Append(hiddenForCheckboxTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ITagHelper"/> implementation targeting all form elements
|
||||
/// to generate content before the form end tag.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[HtmlTargetElement("form")]
|
||||
public class RenderAtEndOfFormTagHelper : TagHelper
|
||||
{
|
||||
public override int Order => -1000;
|
||||
|
||||
[HtmlAttributeNotBound]
|
||||
[ViewContext]
|
||||
public ViewContext ViewContext { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (output == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(output));
|
||||
}
|
||||
|
||||
// Push the new FormContext.
|
||||
ViewContext.FormContext = new FormContext
|
||||
{
|
||||
CanRenderAtEndOfForm = true
|
||||
};
|
||||
|
||||
await context.GetChildContentAsync();
|
||||
|
||||
var formContext = ViewContext.FormContext;
|
||||
if (formContext.HasEndOfFormContent)
|
||||
{
|
||||
foreach (var content in formContext.EndOfFormContent)
|
||||
{
|
||||
output.PostContent.Append(content);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the FormContext
|
||||
ViewContext.FormContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.Extensions.WebEncoders;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
|
|
@ -19,9 +21,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
_viewContext = viewContext;
|
||||
|
||||
// Push the new FormContext; GenerateEndForm() does the corresponding pop.
|
||||
_viewContext.FormContext = new FormContext();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -40,6 +39,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
protected virtual void GenerateEndForm()
|
||||
{
|
||||
RenderEndOfFormContent();
|
||||
_viewContext.Writer.Write("</form>");
|
||||
_viewContext.FormContext = null;
|
||||
}
|
||||
|
|
@ -52,5 +52,33 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
GenerateEndForm();
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderEndOfFormContent()
|
||||
{
|
||||
var formContext = _viewContext.FormContext;
|
||||
if (formContext.HasEndOfFormContent)
|
||||
{
|
||||
var writer = _viewContext.Writer;
|
||||
var htmlWriter = writer as HtmlTextWriter;
|
||||
|
||||
IHtmlEncoder htmlEncoder = null;
|
||||
if (htmlWriter == null)
|
||||
{
|
||||
htmlEncoder = _viewContext.HttpContext.RequestServices.GetRequiredService<IHtmlEncoder>();
|
||||
}
|
||||
|
||||
foreach (var content in formContext.EndOfFormContent)
|
||||
{
|
||||
if (htmlWriter == null)
|
||||
{
|
||||
content.WriteTo(writer, htmlEncoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
htmlWriter.Write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
|
|
@ -11,6 +12,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
private readonly Dictionary<string, bool> _renderedFields =
|
||||
new Dictionary<string, bool>(StringComparer.Ordinal);
|
||||
private Dictionary<string, object> _formData;
|
||||
private IList<IHtmlContent> _endOfFormContent;
|
||||
|
||||
/// <summary>
|
||||
/// Property bag for any information you wish to associate with a <form/> in an
|
||||
|
|
@ -29,6 +31,25 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
}
|
||||
}
|
||||
|
||||
public bool HasFormData => _formData != null;
|
||||
|
||||
public bool HasEndOfFormContent => _endOfFormContent != null;
|
||||
|
||||
public IList<IHtmlContent> EndOfFormContent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_endOfFormContent == null)
|
||||
{
|
||||
_endOfFormContent = new List<IHtmlContent>();
|
||||
}
|
||||
|
||||
return _endOfFormContent;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanRenderAtEndOfForm { get; set; }
|
||||
|
||||
public bool RenderedField(string fieldName)
|
||||
{
|
||||
if (fieldName == null)
|
||||
|
|
|
|||
|
|
@ -272,12 +272,24 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
FormMethod method,
|
||||
object htmlAttributes)
|
||||
{
|
||||
// Push the new FormContext; MvcForm.GenerateEndForm() does the corresponding pop.
|
||||
_viewContext.FormContext = new FormContext
|
||||
{
|
||||
CanRenderAtEndOfForm = true
|
||||
};
|
||||
|
||||
return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributes);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MvcForm BeginRouteForm(string routeName, object routeValues, FormMethod method, object htmlAttributes)
|
||||
{
|
||||
// Push the new FormContext; MvcForm.GenerateEndForm() does the corresponding pop.
|
||||
_viewContext.FormContext = new FormContext
|
||||
{
|
||||
CanRenderAtEndOfForm = true
|
||||
};
|
||||
|
||||
return GenerateRouteForm(routeName, routeValues, method, htmlAttributes);
|
||||
}
|
||||
|
||||
|
|
@ -708,13 +720,24 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
isChecked,
|
||||
htmlAttributes);
|
||||
|
||||
var hidden = _htmlGenerator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, expression);
|
||||
if (checkbox == null || hidden == null)
|
||||
var hiddenForCheckboxTag = _htmlGenerator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, expression);
|
||||
if (checkbox == null || hiddenForCheckboxTag == null)
|
||||
{
|
||||
return HtmlString.Empty;
|
||||
}
|
||||
|
||||
return new BufferedHtmlContent().Append(checkbox).Append(hidden);
|
||||
var checkboxContent = new BufferedHtmlContent().Append(checkbox);
|
||||
|
||||
if (ViewContext.FormContext.CanRenderAtEndOfForm)
|
||||
{
|
||||
ViewContext.FormContext.EndOfFormContent.Add(hiddenForCheckboxTag);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkboxContent.Append(hiddenForCheckboxTag);
|
||||
}
|
||||
|
||||
return checkboxContent;
|
||||
}
|
||||
|
||||
protected virtual string GenerateDisplayName(ModelExplorer modelExplorer, string expression)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ EmployeeName_0</textarea>
|
|||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z0__Remote">Remote</label>
|
||||
<input data-val="true" data-val-required="The Remote field is required." id="z0__Remote" name="[0].Remote" type="checkbox" value="true" /><input name="[0].Remote" type="hidden" value="false" />
|
||||
<input data-val="true" data-val-required="The Remote field is required." id="z0__Remote" name="[0].Remote" type="checkbox" value="true" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z0__OfficeNumber">OfficeNumber</label>
|
||||
|
|
@ -55,7 +55,7 @@ EmployeeName_1</textarea>
|
|||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z1__Remote">Remote</label>
|
||||
<input data-val="true" data-val-required="The Remote field is required." id="z1__Remote" name="[1].Remote" type="checkbox" value="true" /><input name="[1].Remote" type="hidden" value="false" />
|
||||
<input data-val="true" data-val-required="The Remote field is required." id="z1__Remote" name="[1].Remote" type="checkbox" value="true" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z1__OfficeNumber">OfficeNumber</label>
|
||||
|
|
@ -86,7 +86,7 @@ EmployeeName_2</textarea>
|
|||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z2__Remote">Remote</label>
|
||||
<input checked="checked" data-val="true" data-val-required="The Remote field is required." id="z2__Remote" name="[2].Remote" type="checkbox" value="true" /><input name="[2].Remote" type="hidden" value="false" />
|
||||
<input checked="checked" data-val="true" data-val-required="The Remote field is required." id="z2__Remote" name="[2].Remote" type="checkbox" value="true" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z2__OfficeNumber">OfficeNumber</label>
|
||||
|
|
@ -94,5 +94,5 @@ EmployeeName_2</textarea>
|
|||
<option>1002</option>
|
||||
</select>
|
||||
</div> <input type="submit" />
|
||||
</form></body>
|
||||
<input name="[0].Remote" type="hidden" value="false" /><input name="[1].Remote" type="hidden" value="false" /><input name="[2].Remote" type="hidden" value="false" /></form></body>
|
||||
</html>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="HtmlEncode[[NeedSpecialHandle]]">HtmlEncode[[NeedSpecialHandle]]</label>
|
||||
<input checked="HtmlEncode[[checked]]" data-val="HtmlEncode[[true]]" data-val-required="HtmlEncode[[The NeedSpecialHandle field is required.]]" id="HtmlEncode[[NeedSpecialHandle]]" name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[checkbox]]" value="HtmlEncode[[true]]" /><input name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[hidden]]" value="HtmlEncode[[false]]" />
|
||||
<input checked="HtmlEncode[[checked]]" data-val="HtmlEncode[[true]]" data-val-required="HtmlEncode[[The NeedSpecialHandle field is required.]]" id="HtmlEncode[[NeedSpecialHandle]]" name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[checkbox]]" value="HtmlEncode[[true]]" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="order" for="HtmlEncode[[PaymentMethod]]">HtmlEncode[[PaymentMethod]]</label>
|
||||
|
|
@ -75,6 +75,6 @@
|
|||
</ul></div>
|
||||
<input type="HtmlEncode[[hidden]]" id="HtmlEncode[[Customer_Key]]" name="HtmlEncode[[Customer.Key]]" value="HtmlEncode[[KeyA]]" />
|
||||
<input type="submit" />
|
||||
<input name="HtmlEncode[[__RequestVerificationToken]]" type="HtmlEncode[[hidden]]" value="{0}" /></form>
|
||||
<input name="HtmlEncode[[__RequestVerificationToken]]" type="HtmlEncode[[hidden]]" value="{0}" /><input name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[hidden]]" value="HtmlEncode[[false]]" /></form>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="NeedSpecialHandle">NeedSpecialHandle</label>
|
||||
<input checked="checked" data-val="true" data-val-required="The NeedSpecialHandle field is required." id="NeedSpecialHandle" name="NeedSpecialHandle" type="checkbox" value="true" /><input name="NeedSpecialHandle" type="hidden" value="false" />
|
||||
<input checked="checked" data-val="true" data-val-required="The NeedSpecialHandle field is required." id="NeedSpecialHandle" name="NeedSpecialHandle" type="checkbox" value="true" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="order" for="PaymentMethod">PaymentMethod</label>
|
||||
|
|
@ -75,6 +75,6 @@
|
|||
</ul></div>
|
||||
<input type="hidden" id="Customer_Key" name="Customer.Key" value="KeyA" />
|
||||
<input type="submit" />
|
||||
<input name="__RequestVerificationToken" type="hidden" value="{0}" /></form>
|
||||
<input name="__RequestVerificationToken" type="hidden" value="{0}" /><input name="NeedSpecialHandle" type="hidden" value="false" /></form>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="HtmlEncode[[order]]" for="HtmlEncode[[NeedSpecialHandle]]">HtmlEncode[[NeedSpecialHandle]]</label>
|
||||
<input checked="HtmlEncode[[checked]]" data-val="HtmlEncode[[true]]" data-val-required="HtmlEncode[[The NeedSpecialHandle field is required.]]" id="HtmlEncode[[NeedSpecialHandle]]" name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[checkbox]]" value="HtmlEncode[[true]]" /><input name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[hidden]]" value="HtmlEncode[[false]]" />
|
||||
<input checked="HtmlEncode[[checked]]" data-val="HtmlEncode[[true]]" data-val-required="HtmlEncode[[The NeedSpecialHandle field is required.]]" id="HtmlEncode[[NeedSpecialHandle]]" name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[checkbox]]" value="HtmlEncode[[true]]" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="HtmlEncode[[order]]" for="HtmlEncode[[PaymentMethod]]">HtmlEncode[[PaymentMethod]]</label>
|
||||
|
|
@ -74,5 +74,5 @@
|
|||
</ul></div>
|
||||
<input id="HtmlEncode[[Customer_Key]]" name="HtmlEncode[[Customer.Key]]" type="HtmlEncode[[hidden]]" value="HtmlEncode[[KeyA]]" />
|
||||
<input type="submit"/>
|
||||
<input name="HtmlEncode[[__RequestVerificationToken]]" type="HtmlEncode[[hidden]]" value="{0}" /></form></body>
|
||||
<input name="HtmlEncode[[__RequestVerificationToken]]" type="HtmlEncode[[hidden]]" value="{0}" /><input name="HtmlEncode[[NeedSpecialHandle]]" type="HtmlEncode[[hidden]]" value="HtmlEncode[[false]]" /></form></body>
|
||||
</html>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="NeedSpecialHandle">NeedSpecialHandle</label>
|
||||
<input checked="checked" data-val="true" data-val-required="The NeedSpecialHandle field is required." id="NeedSpecialHandle" name="NeedSpecialHandle" type="checkbox" value="true" /><input name="NeedSpecialHandle" type="hidden" value="false" />
|
||||
<input checked="checked" data-val="true" data-val-required="The NeedSpecialHandle field is required." id="NeedSpecialHandle" name="NeedSpecialHandle" type="checkbox" value="true" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="order" for="PaymentMethod">PaymentMethod</label>
|
||||
|
|
@ -74,5 +74,5 @@
|
|||
</ul></div>
|
||||
<input id="Customer_Key" name="Customer.Key" type="hidden" value="KeyA" />
|
||||
<input type="submit"/>
|
||||
<input name="__RequestVerificationToken" type="hidden" value="{0}" /></form></body>
|
||||
<input name="__RequestVerificationToken" type="hidden" value="{0}" /><input name="NeedSpecialHandle" type="hidden" value="false" /></form></body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||
{
|
||||
public class RenderAtEndOfFormTagHelperTest
|
||||
{
|
||||
public static TheoryData RenderAtEndOfFormTagHelperData
|
||||
{
|
||||
get
|
||||
{
|
||||
// tagBuilderList, expectedOutput
|
||||
return new TheoryData<List<TagBuilder>, string>
|
||||
{
|
||||
{
|
||||
new List<TagBuilder>
|
||||
{
|
||||
GetTagBuilder("input", "SomeName", "hidden", "false", TagRenderMode.SelfClosing)
|
||||
},
|
||||
@"<input name=""SomeName"" type=""hidden"" value=""false"" />"
|
||||
},
|
||||
{
|
||||
new List<TagBuilder>
|
||||
{
|
||||
GetTagBuilder("input", "SomeName", "hidden", "false", TagRenderMode.SelfClosing),
|
||||
GetTagBuilder("input", "SomeOtherName", "hidden", "false", TagRenderMode.SelfClosing)
|
||||
},
|
||||
@"<input name=""SomeName"" type=""hidden"" value=""false"" />" +
|
||||
@"<input name=""SomeOtherName"" type=""hidden"" value=""false"" />"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RenderAtEndOfFormTagHelperData))]
|
||||
public async Task Process_AddsHiddenInputTag_FromEndOfFormContent(List<TagBuilder> tagBuilderList, string expectedOutput)
|
||||
{
|
||||
// Arrange
|
||||
var viewContext = new ViewContext();
|
||||
var tagHelperOutput = new TagHelperOutput(
|
||||
tagName: "form",
|
||||
attributes: new TagHelperAttributeList());
|
||||
|
||||
var tagHelperContext = new TagHelperContext(
|
||||
Enumerable.Empty<IReadOnlyTagHelperAttribute>(),
|
||||
new Dictionary<object, object>(),
|
||||
"someId",
|
||||
(useCachedResult) =>
|
||||
{
|
||||
Assert.True(viewContext.FormContext.CanRenderAtEndOfForm);
|
||||
foreach (var item in tagBuilderList)
|
||||
{
|
||||
viewContext.FormContext.EndOfFormContent.Add(item);
|
||||
}
|
||||
|
||||
return Task.FromResult<TagHelperContent>(new DefaultTagHelperContent());
|
||||
});
|
||||
|
||||
var tagHelper = new RenderAtEndOfFormTagHelper
|
||||
{
|
||||
ViewContext = viewContext
|
||||
};
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(context: tagHelperContext, output: tagHelperOutput);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedOutput, tagHelperOutput.PostContent.GetContent());
|
||||
}
|
||||
|
||||
private static TagBuilder GetTagBuilder(string tag, string name, string type, string value, TagRenderMode mode)
|
||||
{
|
||||
var tagBuilder = new TagBuilder(tag);
|
||||
tagBuilder.MergeAttribute("name", name);
|
||||
tagBuilder.MergeAttribute("type", type);
|
||||
tagBuilder.MergeAttribute("value", value);
|
||||
tagBuilder.TagRenderMode = mode;
|
||||
|
||||
return tagBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.TestCommon;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
|
|
@ -127,6 +128,32 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(html));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckBox_WithCanRenderAtEndOfFormSet_DoesNotGenerateInlineHiddenTag()
|
||||
{
|
||||
// Arrange
|
||||
// Mono issue - https://github.com/aspnet/External/issues/19
|
||||
var expected = PlatformNormalizer.NormalizeContent(
|
||||
@"<input checked=""HtmlEncode[[checked]]"" data-val=""HtmlEncode[[true]]"" " +
|
||||
@"data-val-required=""HtmlEncode[[The Boolean field is required.]]"" id=""HtmlEncode[[Property1]]"" " +
|
||||
@"name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" " +
|
||||
@"value=""HtmlEncode[[true]]"" />");
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
|
||||
helper.ViewContext.FormContext.CanRenderAtEndOfForm = true;
|
||||
|
||||
// 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 CommonTestEncoder());
|
||||
Assert.Equal("<input name=\"HtmlEncode[[Property1]]\" type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" />",
|
||||
writer.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckBoxUsesAttemptedValueFromModelState()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,12 +2,15 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#if MOCK_SUPPORT
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.Extensions.WebEncoders;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -318,6 +321,37 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
urlHelper.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndForm_RendersHiddenTagForCheckBox()
|
||||
{
|
||||
// Arrange
|
||||
var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
serviceProvider.Setup(s => s.GetService(typeof(IHtmlEncoder))).Returns(new CommonTestEncoder());
|
||||
var viewContext = htmlHelper.ViewContext;
|
||||
viewContext.HttpContext.RequestServices = serviceProvider.Object;
|
||||
|
||||
var writer = viewContext.Writer as StringWriter;
|
||||
Assert.NotNull(writer);
|
||||
var builder = writer.GetStringBuilder();
|
||||
|
||||
var tagBuilder = new TagBuilder("input");
|
||||
tagBuilder.MergeAttribute("name", "SomeName");
|
||||
tagBuilder.MergeAttribute("type", "hidden");
|
||||
tagBuilder.MergeAttribute("value", "false");
|
||||
tagBuilder.TagRenderMode = TagRenderMode.SelfClosing;
|
||||
|
||||
htmlHelper.ViewContext.FormContext.EndOfFormContent.Add(tagBuilder);
|
||||
|
||||
// Act
|
||||
htmlHelper.EndForm();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
"<input name=\"HtmlEncode[[SomeName]]\" type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" /></form>",
|
||||
builder.ToString());
|
||||
}
|
||||
|
||||
private string GetHtmlAttributesAsString(object htmlAttributes)
|
||||
{
|
||||
var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
@addTagHelper "Microsoft.AspNet.Mvc.TagHelpers.SelectTagHelper, Microsoft.AspNet.Mvc.TagHelpers"
|
||||
@addTagHelper "Microsoft.AspNet.Mvc.TagHelpers.ValidationMessageTagHelper, Microsoft.AspNet.Mvc.TagHelpers"
|
||||
@addTagHelper "Microsoft.AspNet.Mvc.TagHelpers.ValidationSummaryTagHelper, Microsoft.AspNet.Mvc.TagHelpers"
|
||||
@addTagHelper "Microsoft.AspNet.Mvc.TagHelpers.RenderAtEndOfFormTagHelper, Microsoft.AspNet.Mvc.TagHelpers"
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
|
|
|||
Loading…
Reference in New Issue