diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs index 9569468bd2..a4a3425c18 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection; using System.Text.Encodings.Web; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers @@ -30,28 +32,28 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers return Task.CompletedTask; } - protected TagHelperOutput GetInnerTagHelper(TagHelperAttributeList attributeList, TagHelper tagHelper, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) + protected TagHelperOutput GetInnerTagHelper(TagHelperAttributeList attributeList, TagHelperContext context, TagHelper tagHelper, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) { var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run(() => new DefaultTagHelperContent())) { TagMode = tagMode }; - var innerContext = new TagHelperContext(attributeList, new Dictionary(), Guid.NewGuid().ToString()); + var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString()); tagHelper.Process(innerContext, innerOutput); return innerOutput; } - protected string RenderTagHelper(TagHelperAttributeList attributeList, TagHelper tagHelper, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) + protected string RenderTagHelper(TagHelperAttributeList attributeList, TagHelperContext context, TagHelper tagHelper, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) { var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run(() => new DefaultTagHelperContent())) { TagMode = tagMode }; - var innerContext = new TagHelperContext(attributeList, new Dictionary(), Guid.NewGuid().ToString()); + var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString()); tagHelper.Process(innerContext, innerOutput); @@ -66,5 +68,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers return writer.ToString(); } } + + public static T GetAttribute(ModelExplorer property) where T : Attribute + { + var xd1 = property.Container.ModelType.GetTypeInfo(); + var xd2 = xd1.GetProperty(property.Metadata.PropertyName); + + if (xd2 == null) + { + return null; + } + + var attribute = xd2 .GetCustomAttribute(); + + return attribute; + } } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs index b59eb269de..3f8889a477 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs @@ -13,7 +13,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { private readonly HtmlEncoder _htmlEncoder; private readonly AbpInputTagHelper _abpInputTagHelper; - private const string SelectItemsPostFix = "selectitems"; public AbpDynamicFormTagHelperService(HtmlEncoder htmlEncoder, AbpInputTagHelper abpInputTagHelper) { @@ -23,44 +22,45 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { + var list = new List(); + context.Items.Add("InputGroupContents", list); + output.TagName = "form"; output.Attributes.Add("method", "post"); output.Attributes.Add("action", "#"); - var inputsAsHtml = await GetInputsAsHtml(output); - output.PreContent.SetHtmlContent(inputsAsHtml); + await output.GetChildContentAsync(); + ProcessFields(context, output); + + foreach (var itemConfig in list.OrderBy(o => o.Order)) + { + output.PostContent.SetHtmlContent(output.PostContent.GetContent() + itemConfig.Html); + } } - protected virtual async Task GetInputsAsHtml(TagHelperOutput output) + protected virtual void ProcessFields(TagHelperContext context, TagHelperOutput output) { - var inputsAsHtml = ""; - var models = await GetModels(output); + var models = GetModels(context, output); foreach (var model in models) { - inputsAsHtml += ProcessInputGroup(model); + ProcessInputGroup(context, model); } - - return inputsAsHtml; } - protected virtual async Task> GetModels(TagHelperOutput output) + protected virtual List GetModels(TagHelperContext context, TagHelperOutput output) { - - var models = ExploreModelsRecursively(new List(), TagHelper.Model.ModelExplorer); - - return await RemoveOverridenFieldsAndGetModels(output, models); + return ExploreModelsRecursively(new List(), TagHelper.Model.ModelExplorer); } - protected virtual string ProcessInputGroup(ModelExpression model) + protected virtual void ProcessInputGroup(TagHelperContext context, ModelExpression model) { _abpInputTagHelper.AspFor = model; _abpInputTagHelper.Label = ""; _abpInputTagHelper.ViewContext = TagHelper.ViewContext; - return RenderTagHelper(new TagHelperAttributeList(), _abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag) - + Environment.NewLine; + RenderTagHelper(new TagHelperAttributeList(), context, _abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag); } protected virtual List ExploreModelsRecursively(List list, ModelExplorer model) @@ -106,11 +106,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form type == typeof(long) || type.IsEnum; } - - protected virtual async Task> RemoveOverridenFieldsAndGetModels(TagHelperOutput output, List models) - { - var overridenFormElementsProcessed = (await output.GetChildContentAsync()).GetContent(); - return models.Where(m => !overridenFormElementsProcessed.Contains("id=\"" + m.Name.Replace('.','_') + "\"")).ToList(); - } } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormGroupTagHelperService.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormGroupTagHelperService.cs index 2a5e251766..22b9b95d22 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormGroupTagHelperService.cs +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormGroupTagHelperService.cs @@ -6,15 +6,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { public class AbpFormGroupTagHelperService : AbpTagHelperService { - private readonly HtmlEncoder _htmlEncoder; - private readonly AbpInputTagHelper _abpInputTagHelper; - - public AbpFormGroupTagHelperService(HtmlEncoder htmlEncoder, AbpInputTagHelper abpInputTagHelper) - { - _htmlEncoder = htmlEncoder; - _abpInputTagHelper = abpInputTagHelper; - } - public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "div"; @@ -24,6 +15,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form output.Attributes.AddClass("form-check"); } } - } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs index a2f157be30..3d038a415d 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs @@ -11,6 +11,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public string Label { get; set; } + [HtmlAttributeName("order")] + public int? FieldOrder { get; set; } + [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 7b73eabb89..93e34a5871 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text.Encodings.Web; using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; @@ -24,32 +27,35 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public override void Process(TagHelperContext context, TagHelperOutput output) { - output.TagName = "div"; - output.TagMode = TagMode.StartTagAndEndTag; - - var inputTag = GetInputTag(); + var inputTag = GetInputTag(context); var inputHtml = RenderTagHelperOutput(inputTag, _encoder); var isCheckbox = IsInputCheckbox(inputTag.Attributes); - var label = GetLabelAsHtml(inputTag, isCheckbox); var content = isCheckbox ? inputHtml + Environment.NewLine + label : label + Environment.NewLine + inputHtml; - output.Content.SetHtmlContent(content); + content ="
" + Environment.NewLine + content + Environment.NewLine + "
"; - SetDivAttributes(output, isCheckbox); - } - - protected virtual void SetDivAttributes(TagHelperOutput output, bool isCheckbox) - { - output.Attributes.RemoveAll("asp-for"); - output.Attributes.Add("class", isCheckbox ? " form-check" : "form-group"); + //var order = GetAttribute(TagHelper.AspFor.ModelExplorer); + + var list = context.Items["InputGroupContents"] as List; + + if (list != null && !list.Any(igc =>igc.Html.Contains("id=\"" + TagHelper.AspFor.Name.Replace('.', '_') + "\""))) + { + list.Add(new InputGroupContent + { + Html = content, + Order = TagHelper.FieldOrder ?? 999 + }); + } + + output.SuppressOutput(); } - protected virtual TagHelperOutput GetInputTag() + protected virtual TagHelperOutput GetInputTag(TagHelperContext context) { var inputTagHelper = new InputTagHelper(_generator) { @@ -57,8 +63,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form ViewContext = TagHelper.ViewContext }; - var inputTagHelperOutput = GetInnerTagHelper(new TagHelperAttributeList(), inputTagHelper, "input"); ; - + var inputTagHelperOutput = GetInnerTagHelper(new TagHelperAttributeList(), context, inputTagHelper, "input"); + inputTagHelperOutput.Attributes.Add("class", IsInputCheckbox(inputTagHelperOutput.Attributes) ? "form-check-input" : "form-control"); diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index 316a141e8b..27ad072108 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form SetDivAttributes(output); output.TagMode = TagMode.StartTagAndEndTag; - var selectTag = GetSelectTag(); + var selectTag = GetSelectTag(context); var seelctAsHtml = RenderTagHelperOutput(selectTag, _encoder); var labelAsHtml = GetLabelAsHtml(selectTag); @@ -44,7 +44,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form output.Attributes.Add("class", "form-group"); } - protected virtual TagHelperOutput GetSelectTag() + protected virtual TagHelperOutput GetSelectTag(TagHelperContext context) { var selectTagHelper = new SelectTagHelper(_generator) { @@ -54,7 +54,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form }; var attributes = new TagHelperAttributeList { new TagHelperAttribute("class", "form-control") }; - var inputTagHelperOutput = GetInnerTagHelper(attributes, selectTagHelper, "select", TagMode.StartTagAndEndTag); ; + var inputTagHelperOutput = GetInnerTagHelper(attributes, context,selectTagHelper, "select", TagMode.StartTagAndEndTag); ; inputTagHelperOutput.Attributes.Add("class", "form-control"); diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisplayOrder.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisplayOrder.cs new file mode 100644 index 0000000000..7f311790d9 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisplayOrder.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form +{ + [AttributeUsage(AttributeTargets.Property)] + public class DisplayOrder : Attribute + { + public int Number { get; set; } + + public DisplayOrder(int number) + { + Number = number; + } + } +} diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputGroupContent.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputGroupContent.cs new file mode 100644 index 0000000000..06694dbf9a --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputGroupContent.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form +{ + public class InputGroupContent + { + public string Html { get; set; } + + public int Order { get; set; } + } +} \ No newline at end of file diff --git a/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml b/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml index 66da21ce04..711621d0d9 100644 --- a/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml +++ b/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml @@ -16,7 +16,8 @@ - + +
@@ -28,7 +29,7 @@
-

# Input Group Example

+@*

# Input Group Example

@@ -59,7 +60,7 @@ </form>
-
+*@ @*
diff --git a/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml.cs b/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml.cs index d6e8a25b44..d2ac31c34a 100644 --- a/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml.cs +++ b/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml.cs @@ -5,42 +5,44 @@ using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components { public class FormsModel : PageModel { - [Required] - [DisplayName("Name")] - public string Name { get; set; } + //[Required] + //[DisplayName("Name")] + //public string Name { get; set; } - [Required] - [EmailAddress] - [DisplayName("Email")] - public string EmailAddress { get; set; } + //[Required] + //[EmailAddress] + //[DisplayName("Email")] + //public string EmailAddress { get; set; } - [DataType(DataType.Password)] - public string Password { get; set; } = "MyPass"; + //[DataType(DataType.Password)] + //public string Password { get; set; } = "MyPass"; - [Phone] - [DisplayName("Phone Number")] - public string PhoneNumber { get; set; } + //[Phone] + //[DisplayName("Phone Number")] + //[DisplayOrder(4)] + //public string PhoneNumber { get; set; } - [DisplayName("Count")] - public int Count { get; set; } + //[DisplayName("Count")] + //public int Count { get; set; } - [DataType(DataType.Date)] - [DisplayName("Day")] - public DateTime Day { get; set; } + //[DataType(DataType.Date)] + //[DisplayName("Day")] + //public DateTime Day { get; set; } - [DisplayName("Is Active")] - public bool IsActive { get; set; } + //[DisplayName("Is Active")] + //public bool IsActive { get; set; } - [DisplayName("Country")] - public string Country { get; set; } + //[DisplayName("Country")] + //public string Country { get; set; } - [DisplayName("City")] - public Cities City { get; set; } + //[DisplayName("City")] + //public Cities City { get; set; } public Person Person { get; set; } @@ -55,10 +57,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components public void OnGet() { - Name = "MyName"; - Day = DateTime.Today; - //var htmlHelper = new HtmlHelper(); - //EnumCityList = htmlHelper.GetEnumSelectList(typeof(Cities)); } } @@ -83,6 +81,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components [DisplayName("City")] public Cities City { get; set; } + [DisplayOrder(51)] public Phone Phone { get; set; } [DataType(DataType.Date)]