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.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<TagHelperContent>(() => new DefaultTagHelperContent()))
{
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);
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()))
{
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);
@ -66,5 +68,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
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 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<InputGroupContent>();
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<string> 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<List<ModelExpression>> GetModels(TagHelperOutput output)
protected virtual List<ModelExpression> GetModels(TagHelperContext context, TagHelperOutput output)
{
var models = ExploreModelsRecursively(new List<ModelExpression>(), TagHelper.Model.ModelExplorer);
return await RemoveOverridenFieldsAndGetModels(output, models);
return ExploreModelsRecursively(new List<ModelExpression>(), 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<ModelExpression> ExploreModelsRecursively(List<ModelExpression> 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<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>
{
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");
}
}
}
}

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

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);
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");

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-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>
</div>
<div class="code-area">
@ -28,7 +29,7 @@
</div>
<h4># Input Group Example</h4>
@*<h4># Input Group Example</h4>
<div class="demo-with-code">
<div class="demo-area">
@ -59,7 +60,7 @@
&lt;/form&gt;
</pre>
</div>
</div>
</div>*@
@*<div class="demo-with-code">
<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.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)]

Loading…
Cancel
Save