diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 1fb6f806e1..f40ff1030b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -54,7 +54,7 @@ public class AbpInputTagHelperService : AbpTagHelperService 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 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 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 "
" + Environment.NewLine + innerHtml + Environment.NewLine + "
"; @@ -516,6 +518,11 @@ public class AbpInputTagHelperService : AbpTagHelperService 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"); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj index 19dae03734..654b6b0d0c 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj @@ -18,6 +18,7 @@ + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/TagHelpers/Form/AbpInputTagHelperService_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/TagHelpers/Form/AbpInputTagHelperService_Tests.cs new file mode 100644 index 0000000000..33e2e35bec --- /dev/null +++ b/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(), + "test"); + } + + private static TagHelperOutput CreateOutput() + { + return new TagHelperOutput( + "abp-input", + new TagHelperAttributeList(), + (_, _) => Task.FromResult(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(new DefaultTagHelperContent())); + + inputTagHelperOutput.TagMode = TagMode.SelfClosing; + + return Task.FromResult((inputTagHelperOutput, false)); + } + + protected override Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) + { + return Task.FromResult(string.Empty); + } + + protected override Task 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; + } + } +} diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml index ab44e878c7..544925e53b 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml @@ -317,7 +317,7 @@ public class DynamicFormsModel : PageModel

 <form method="post">
-    <div class="mb-3">
+    <div>
         <input type="hidden" id="MyAttributeExamplesModel_HiddenInput" name="MyAttributeExamplesModel.HiddenInput" value="" class="form-control ">
     </div>
     <div class="mb-3">
@@ -433,4 +433,4 @@ public class DynamicFormsModel : PageModel
 
 
-@await Component.InvokeAsync("TagHelperProperties", typeof(AbpDynamicFormTagHelper)) \ No newline at end of file +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpDynamicFormTagHelper))