Browse Source

Tag Helper form improvements

pull/272/head
yekalkan 9 years ago
parent
commit
85620a97bc
  1. 25
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs
  2. 40
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  3. 10
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormGroupTagHelperService.cs
  4. 3
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs
  5. 38
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  6. 6
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  7. 18
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisplayOrder.cs
  8. 9
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputGroupContent.cs
  9. 7
      test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml
  10. 53
      test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml.cs

25
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
@ -30,28 +32,28 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
return Task.CompletedTask; 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<TagHelperContent>(() => new DefaultTagHelperContent())) var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run<TagHelperContent>(() => new DefaultTagHelperContent()))
{ {
TagMode = tagMode TagMode = tagMode
}; };
var innerContext = new TagHelperContext(attributeList, new Dictionary<object, object>(), Guid.NewGuid().ToString()); var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Process(innerContext, innerOutput); tagHelper.Process(innerContext, innerOutput);
return 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<TagHelperContent>(() => new DefaultTagHelperContent())) var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run<TagHelperContent>(() => new DefaultTagHelperContent()))
{ {
TagMode = tagMode TagMode = tagMode
}; };
var innerContext = new TagHelperContext(attributeList, new Dictionary<object, object>(), Guid.NewGuid().ToString()); var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Process(innerContext, innerOutput); tagHelper.Process(innerContext, innerOutput);
@ -66,5 +68,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
return writer.ToString(); return writer.ToString();
} }
} }
public static T GetAttribute<T>(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<T>();
return attribute;
}
} }
} }

40
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 HtmlEncoder _htmlEncoder;
private readonly AbpInputTagHelper _abpInputTagHelper; private readonly AbpInputTagHelper _abpInputTagHelper;
private const string SelectItemsPostFix = "selectitems";
public AbpDynamicFormTagHelperService(HtmlEncoder htmlEncoder, AbpInputTagHelper abpInputTagHelper) 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) public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{ {
var list = new List<InputGroupContent>();
context.Items.Add("InputGroupContents", list);
output.TagName = "form"; output.TagName = "form";
output.Attributes.Add("method", "post"); output.Attributes.Add("method", "post");
output.Attributes.Add("action", "#"); 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<string> GetInputsAsHtml(TagHelperOutput output) protected virtual void ProcessFields(TagHelperContext context, TagHelperOutput output)
{ {
var inputsAsHtml = ""; var models = GetModels(context, output);
var models = await GetModels(output);
foreach (var model in models) foreach (var model in models)
{ {
inputsAsHtml += ProcessInputGroup(model); ProcessInputGroup(context, model);
} }
return inputsAsHtml;
} }
protected virtual async Task<List<ModelExpression>> GetModels(TagHelperOutput output) protected virtual List<ModelExpression> GetModels(TagHelperContext context, TagHelperOutput output)
{ {
return ExploreModelsRecursively(new List<ModelExpression>(), TagHelper.Model.ModelExplorer);
var models = ExploreModelsRecursively(new List<ModelExpression>(), TagHelper.Model.ModelExplorer);
return await RemoveOverridenFieldsAndGetModels(output, models);
} }
protected virtual string ProcessInputGroup(ModelExpression model) protected virtual void ProcessInputGroup(TagHelperContext context, ModelExpression model)
{ {
_abpInputTagHelper.AspFor = model; _abpInputTagHelper.AspFor = model;
_abpInputTagHelper.Label = ""; _abpInputTagHelper.Label = "";
_abpInputTagHelper.ViewContext = TagHelper.ViewContext; _abpInputTagHelper.ViewContext = TagHelper.ViewContext;
return RenderTagHelper(new TagHelperAttributeList(), _abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag) RenderTagHelper(new TagHelperAttributeList(), context, _abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
+ Environment.NewLine;
} }
protected virtual List<ModelExpression> ExploreModelsRecursively(List<ModelExpression> list, ModelExplorer model) protected virtual List<ModelExpression> ExploreModelsRecursively(List<ModelExpression> list, ModelExplorer model)
@ -106,11 +106,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
type == typeof(long) || type == typeof(long) ||
type.IsEnum; type.IsEnum;
} }
protected virtual async Task<List<ModelExpression>> RemoveOverridenFieldsAndGetModels(TagHelperOutput output, List<ModelExpression> models)
{
var overridenFormElementsProcessed = (await output.GetChildContentAsync()).GetContent();
return models.Where(m => !overridenFormElementsProcessed.Contains("id=\"" + m.Name.Replace('.','_') + "\"")).ToList();
}
} }
} }

10
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<AbpFormGroupTagHelper> public class AbpFormGroupTagHelperService : AbpTagHelperService<AbpFormGroupTagHelper>
{ {
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) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
output.TagName = "div"; output.TagName = "div";
@ -24,6 +15,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.Attributes.AddClass("form-check"); output.Attributes.AddClass("form-check");
} }
} }
} }
} }

3
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; } public string Label { get; set; }
[HtmlAttributeName("order")]
public int? FieldOrder { get; set; }
[HtmlAttributeNotBound] [HtmlAttributeNotBound]
[ViewContext] [ViewContext]
public ViewContext ViewContext { get; set; } public ViewContext ViewContext { get; set; }

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

@ -1,7 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using Localization.Resources.AbpUi; using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; 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) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
output.TagName = "div"; var inputTag = GetInputTag(context);
output.TagMode = TagMode.StartTagAndEndTag;
var inputTag = GetInputTag();
var inputHtml = RenderTagHelperOutput(inputTag, _encoder); var inputHtml = RenderTagHelperOutput(inputTag, _encoder);
var isCheckbox = IsInputCheckbox(inputTag.Attributes); var isCheckbox = IsInputCheckbox(inputTag.Attributes);
var label = GetLabelAsHtml(inputTag, isCheckbox); var label = GetLabelAsHtml(inputTag, isCheckbox);
var content = isCheckbox ? var content = isCheckbox ?
inputHtml + Environment.NewLine + label : inputHtml + Environment.NewLine + label :
label + Environment.NewLine + inputHtml; label + Environment.NewLine + inputHtml;
output.Content.SetHtmlContent(content); content ="<div class=\""+(isCheckbox ? "form-check" : "form-group") +"\">" + Environment.NewLine + content + Environment.NewLine + "</div>";
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<DisplayOrder>(TagHelper.AspFor.ModelExplorer);
var list = context.Items["InputGroupContents"] as List<InputGroupContent>;
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) var inputTagHelper = new InputTagHelper(_generator)
{ {
@ -57,8 +63,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext ViewContext = TagHelper.ViewContext
}; };
var inputTagHelperOutput = GetInnerTagHelper(new TagHelperAttributeList(), inputTagHelper, "input"); ; var inputTagHelperOutput = GetInnerTagHelper(new TagHelperAttributeList(), context, inputTagHelper, "input");
inputTagHelperOutput.Attributes.Add("class", inputTagHelperOutput.Attributes.Add("class",
IsInputCheckbox(inputTagHelperOutput.Attributes) ? "form-check-input" : "form-control"); IsInputCheckbox(inputTagHelperOutput.Attributes) ? "form-check-input" : "form-control");

6
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); SetDivAttributes(output);
output.TagMode = TagMode.StartTagAndEndTag; output.TagMode = TagMode.StartTagAndEndTag;
var selectTag = GetSelectTag(); var selectTag = GetSelectTag(context);
var seelctAsHtml = RenderTagHelperOutput(selectTag, _encoder); var seelctAsHtml = RenderTagHelperOutput(selectTag, _encoder);
var labelAsHtml = GetLabelAsHtml(selectTag); var labelAsHtml = GetLabelAsHtml(selectTag);
@ -44,7 +44,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.Attributes.Add("class", "form-group"); output.Attributes.Add("class", "form-group");
} }
protected virtual TagHelperOutput GetSelectTag() protected virtual TagHelperOutput GetSelectTag(TagHelperContext context)
{ {
var selectTagHelper = new SelectTagHelper(_generator) 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 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"); inputTagHelperOutput.Attributes.Add("class", "form-control");

18
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;
}
}
}

9
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; }
}
}

7
test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml

@ -16,7 +16,8 @@
<abp-dynamic-form model="@Model.Person"> <abp-dynamic-form model="@Model.Person">
<abp-input asp-for="@Model.Person.Name" /> <abp-input asp-for="@Model.Person.Name" />
<abp-input asp-for="@Model.Person.Age" /> <abp-input asp-for="@Model.Person.Age" order="9999" />
<abp-input asp-for="@Model.Person.Phone.Number" order="1" />
</abp-dynamic-form> </abp-dynamic-form>
</div> </div>
<div class="code-area"> <div class="code-area">
@ -28,7 +29,7 @@
</div> </div>
<h4># Input Group Example</h4> @*<h4># Input Group Example</h4>
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">
@ -59,7 +60,7 @@
&lt;/form&gt; &lt;/form&gt;
</pre> </pre>
</div> </div>
</div> </div>*@
@*<div class="demo-with-code"> @*<div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">

53
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.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
{ {
public class FormsModel : PageModel public class FormsModel : PageModel
{ {
[Required] //[Required]
[DisplayName("Name")] //[DisplayName("Name")]
public string Name { get; set; } //public string Name { get; set; }
[Required] //[Required]
[EmailAddress] //[EmailAddress]
[DisplayName("Email")] //[DisplayName("Email")]
public string EmailAddress { get; set; } //public string EmailAddress { get; set; }
[DataType(DataType.Password)] //[DataType(DataType.Password)]
public string Password { get; set; } = "MyPass"; //public string Password { get; set; } = "MyPass";
[Phone] //[Phone]
[DisplayName("Phone Number")] //[DisplayName("Phone Number")]
public string PhoneNumber { get; set; } //[DisplayOrder(4)]
//public string PhoneNumber { get; set; }
[DisplayName("Count")] //[DisplayName("Count")]
public int Count { get; set; } //public int Count { get; set; }
[DataType(DataType.Date)] //[DataType(DataType.Date)]
[DisplayName("Day")] //[DisplayName("Day")]
public DateTime Day { get; set; } //public DateTime Day { get; set; }
[DisplayName("Is Active")] //[DisplayName("Is Active")]
public bool IsActive { get; set; } //public bool IsActive { get; set; }
[DisplayName("Country")] //[DisplayName("Country")]
public string Country { get; set; } //public string Country { get; set; }
[DisplayName("City")] //[DisplayName("City")]
public Cities City { get; set; } //public Cities City { get; set; }
public Person Person { get; set; } public Person Person { get; set; }
@ -55,10 +57,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
public void OnGet() 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")] [DisplayName("City")]
public Cities City { get; set; } public Cities City { get; set; }
[DisplayOrder(51)]
public Phone Phone { get; set; } public Phone Phone { get; set; }
[DataType(DataType.Date)] [DataType(DataType.Date)]

Loading…
Cancel
Save