Browse Source

fix: avoid spacing for hidden MVC inputs (#25095)

* fix: avoid spacing for hidden MVC inputs

* fix: preserve MVC input tag helper extensibility

* refactor: simplify hidden input spacing fix using context.Items

---------

Co-authored-by: maliming <malimings@gmail.com>
pull/25096/head
Enis Necipoglu 2 weeks ago
committed by GitHub
parent
commit
89f5f5f7bc
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  2. 1
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj
  3. 122
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/TagHelpers/Form/AbpInputTagHelperService_Tests.cs
  4. 4
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs

@ -54,7 +54,7 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
output.TagMode = TagMode.StartTagAndEndTag;
output.TagName = "div";
LeaveOnlyGroupAttributes(context, output);
if (!IsOutputHidden(output))
if (!IsInputHidden(context))
{
if (TagHelper.FloatingLabel && !isCheckBox)
{
@ -86,6 +86,7 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
protected virtual async Task<(string, bool)> GetFormInputGroupAsHtmlAsync(TagHelperContext context, TagHelperOutput output)
{
var (inputTag, isCheckBox) = await GetInputTagHelperOutputAsync(context, output);
context.Items[nameof(IsOutputHidden)] = IsOutputHidden(inputTag);
var inputHtml = inputTag.Render(_encoder);
var label = await GetLabelAsHtmlAsync(context, output, inputTag, isCheckBox);
@ -124,7 +125,8 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox)
{
var mb = TagHelper.AddMarginBottomClass ? (isCheckbox ? "mb-2" : "mb-3") : string.Empty;
var isHidden = IsInputHidden(context);
var mb = !isHidden && TagHelper.AddMarginBottomClass ? (isCheckbox ? "mb-2" : "mb-3") : string.Empty;
return "<div class=\"" + (isCheckbox ? $"custom-checkbox custom-control {mb} form-check" : $"{mb}") + "\">" +
Environment.NewLine + innerHtml + Environment.NewLine +
"</div>";
@ -516,6 +518,11 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
return inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString()!.ToLowerInvariant() == "hidden");
}
protected virtual bool IsInputHidden(TagHelperContext context)
{
return context.Items.TryGetValue(nameof(IsOutputHidden), out var val) && val is true;
}
protected virtual string GetIdAttributeValue(TagHelperOutput inputTag)
{
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");

1
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj

@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Mvc.UI.Bundling\Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Tests\Volo.Abp.AspNetCore.Tests.csproj" />

122
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/TagHelpers/Form/AbpInputTagHelperService_Tests.cs

@ -0,0 +1,122 @@
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Shouldly;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
public class AbpInputTagHelperService_Tests
{
[Fact]
public async Task Hidden_inputs_should_not_add_margin_bottom_classes()
{
var service = new TestAbpInputTagHelperService("hidden");
var tagHelper = new AbpInputTagHelper(service)
{
AspFor = CreateModelExpression()
};
var output = CreateOutput();
await tagHelper.ProcessAsync(CreateContext(), output);
output.Attributes.ContainsName("class").ShouldBeFalse();
service.LastGroupHtml.ShouldNotContain("mb-3");
}
[Fact]
public async Task Visible_inputs_should_keep_margin_bottom_classes()
{
var service = new TestAbpInputTagHelperService("text");
var tagHelper = new AbpInputTagHelper(service)
{
AspFor = CreateModelExpression()
};
var output = CreateOutput();
await tagHelper.ProcessAsync(CreateContext(), output);
output.Attributes["class"].Value.ShouldBe("mb-3");
service.LastGroupHtml.ShouldContain("mb-3");
}
private static TagHelperContext CreateContext()
{
return new TagHelperContext(
new TagHelperAttributeList(),
new Dictionary<object, object>(),
"test");
}
private static TagHelperOutput CreateOutput()
{
return new TagHelperOutput(
"abp-input",
new TagHelperAttributeList(),
(_, _) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
}
private static ModelExpression CreateModelExpression()
{
var metadataProvider = new EmptyModelMetadataProvider();
return new ModelExpression(
"HiddenInput",
metadataProvider.GetModelExplorerForType(typeof(string), null));
}
private sealed class TestAbpInputTagHelperService : AbpInputTagHelperService
{
private readonly string _inputTypeName;
public string LastGroupHtml { get; private set; } = string.Empty;
public TestAbpInputTagHelperService(string inputTypeName)
: base(null!, HtmlEncoder.Default, null!)
{
_inputTypeName = inputTypeName;
}
protected override Task<(TagHelperOutput, bool)> GetInputTagHelperOutputAsync(TagHelperContext context, TagHelperOutput output)
{
var inputTagHelperOutput = new TagHelperOutput(
"input",
new TagHelperAttributeList
{
{ "type", _inputTypeName },
{ "id", "HiddenInput" },
{ "class", "form-control" }
},
(_, _) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
inputTagHelperOutput.TagMode = TagMode.SelfClosing;
return Task.FromResult((inputTagHelperOutput, false));
}
protected override Task<string> GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
{
return Task.FromResult(string.Empty);
}
protected override Task<string> GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
{
return Task.FromResult(string.Empty);
}
protected override string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
{
return string.Empty;
}
protected override void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool suppress)
{
LastGroupHtml = html;
suppress = false;
}
}
}

4
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml

@ -317,7 +317,7 @@ public class DynamicFormsModel : PageModel
<abp-tab title="Rendered">
<pre><code>
&lt;form method=&quot;post&quot;&gt;
&lt;div class=&quot;mb-3&quot;&gt;
&lt;div&gt;
&lt;input type=&quot;hidden&quot; id=&quot;MyAttributeExamplesModel_HiddenInput&quot; name=&quot;MyAttributeExamplesModel.HiddenInput&quot; value=&quot;&quot; class=&quot;form-control &quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;mb-3&quot;&gt;
@ -433,4 +433,4 @@ public class DynamicFormsModel : PageModel
<hr />
@await Component.InvokeAsync("TagHelperProperties", typeof(AbpDynamicFormTagHelper))
@await Component.InvokeAsync("TagHelperProperties", typeof(AbpDynamicFormTagHelper))

Loading…
Cancel
Save