Browse Source

Form Tag helper improvements

pull/272/head
yekalkan 9 years ago
parent
commit
794932cb7d
  1. 2
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs
  2. 81
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  3. 4
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  4. 31
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  5. 30
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/SelectItems.cs
  6. 70
      test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml
  7. 62
      test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Forms.cshtml.cs

2
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs

@ -6,8 +6,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
public class AbpDynamicFormTagHelper : AbpTagHelper<AbpDynamicFormTagHelper, AbpDynamicFormTagHelperService> public class AbpDynamicFormTagHelper : AbpTagHelper<AbpDynamicFormTagHelper, AbpDynamicFormTagHelperService>
{ {
[HtmlAttributeName("asp-model")]
public ModelExpression Model { get; set; } public ModelExpression Model { get; set; }
[HtmlAttributeNotBound] [HtmlAttributeNotBound]
[ViewContext] [ViewContext]

81
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
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.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
@ -13,11 +14,13 @@ 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 readonly AbpSelectTagHelper _abpSelectTagHelper;
public AbpDynamicFormTagHelperService(HtmlEncoder htmlEncoder, AbpInputTagHelper abpInputTagHelper) public AbpDynamicFormTagHelperService(HtmlEncoder htmlEncoder, AbpInputTagHelper abpInputTagHelper, AbpSelectTagHelper abpSelectTagHelper)
{ {
_htmlEncoder = htmlEncoder; _htmlEncoder = htmlEncoder;
_abpInputTagHelper = abpInputTagHelper; _abpInputTagHelper = abpInputTagHelper;
_abpSelectTagHelper = abpSelectTagHelper;
} }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
@ -45,13 +48,24 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
foreach (var model in models) foreach (var model in models)
{ {
if (IsSelectGroup(context, model, out var selectItems))
{
ProcessSelectGroup(context, model, selectItems);
continue;
}
ProcessInputGroup(context, model); ProcessInputGroup(context, model);
} }
} }
protected virtual List<ModelExpression> GetModels(TagHelperContext context, TagHelperOutput output) protected virtual void ProcessSelectGroup(TagHelperContext context, ModelExpression model, IEnumerable<SelectListItem> selectItems)
{ {
return ExploreModelsRecursively(new List<ModelExpression>(), TagHelper.Model.ModelExplorer); _abpSelectTagHelper.AspFor = model;
_abpSelectTagHelper.AspItems = selectItems;
_abpSelectTagHelper.Label = "";
_abpSelectTagHelper.ViewContext = TagHelper.ViewContext;
RenderTagHelper(new TagHelperAttributeList(), context, _abpSelectTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
} }
protected virtual void ProcessInputGroup(TagHelperContext context, ModelExpression model) protected virtual void ProcessInputGroup(TagHelperContext context, ModelExpression model)
@ -63,6 +77,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
RenderTagHelper(new TagHelperAttributeList(), context, _abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag); RenderTagHelper(new TagHelperAttributeList(), context, _abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
} }
protected virtual List<ModelExpression> GetModels(TagHelperContext context, TagHelperOutput output)
{
return TagHelper.Model.ModelExplorer.Properties.Aggregate(new List<ModelExpression>(), ExploreModelsRecursively);
}
protected virtual List<ModelExpression> ExploreModelsRecursively(List<ModelExpression> list, ModelExplorer model) protected virtual List<ModelExpression> ExploreModelsRecursively(List<ModelExpression> list, ModelExplorer model)
{ {
if (IsCsharpClassOrPrimitive(model.ModelType)) if (IsCsharpClassOrPrimitive(model.ModelType))
@ -71,6 +90,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return list; return list;
} }
if (IsListOfSelectItem(model.ModelType))
{
return list;
}
return model.Properties.Aggregate(list, ExploreModelsRecursively); return model.Properties.Aggregate(list, ExploreModelsRecursively);
} }
@ -78,13 +102,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
var temp = explorer; var temp = explorer;
var propertyName = explorer.Metadata.PropertyName; var propertyName = explorer.Metadata.PropertyName;
while (temp?.Container?.Metadata?.PropertyName != null) while (temp?.Container?.Metadata?.PropertyName != null)
{ {
temp = temp.Container; temp = temp.Container;
propertyName = temp.Metadata.PropertyName + "." + propertyName; propertyName = temp.Metadata.PropertyName + "." + propertyName;
} }
return new ModelExpression(propertyName, explorer); return new ModelExpression(propertyName, explorer);
} }
@ -94,17 +118,52 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
type.IsValueType || type.IsValueType ||
type == typeof(DateTime) || type == typeof(DateTime) ||
type == typeof(ValueType) || type == typeof(ValueType) ||
type == typeof(string) || type == typeof(String) ||
type == typeof(decimal) || type == typeof(Decimal) ||
type == typeof(double) || type == typeof(Double) ||
type == typeof(Guid) || type == typeof(Guid) ||
type == typeof(Char) ||
type == typeof(Byte) ||
type == typeof(Boolean) ||
type == typeof(TimeSpan) || type == typeof(TimeSpan) ||
type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset) ||
type == typeof(Int16) ||
type == typeof(Int32) ||
type == typeof(Int64) ||
type == typeof(ushort) ||
type == typeof(uint) ||
type == typeof(ulong) ||
type == typeof(float) || type == typeof(float) ||
type == typeof(short) ||
type == typeof(int) ||
type == typeof(long) ||
type.IsEnum; type.IsEnum;
} }
protected virtual bool IsListOfSelectItem(Type type)
{
return type == typeof(List<SelectListItem>) || type == typeof(IEnumerable<SelectListItem>);
}
protected virtual bool IsSelectGroup(TagHelperContext context, ModelExpression model, out IEnumerable<SelectListItem> selectItems)
{
return IsEnum(model.ModelExplorer, out selectItems) || AreSelectItemsProvided(model.ModelExplorer, out selectItems);
}
protected virtual bool IsEnum(ModelExplorer explorer, out IEnumerable<SelectListItem> selectItems)
{
selectItems = explorer.Metadata.IsEnum ? GetSelectItemsFromEnum(explorer.ModelType) : null;
return explorer.Metadata.IsEnum;
}
protected virtual IEnumerable<SelectListItem> GetSelectItemsFromEnum(Type enumType)
{
return enumType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static)
.Select((t, i) => new SelectListItem { Value = i.ToString(), Text = t.Name }).ToList();
}
protected virtual bool AreSelectItemsProvided(ModelExplorer explorer, out IEnumerable<SelectListItem> selectItems)
{
selectItems = GetAttribute<SelectItems>(explorer)?.GetItems(explorer);
return selectItems != null;
}
} }
} }

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

@ -52,11 +52,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetContent(string label, string inputHtml, bool isCheckbox) protected virtual string GetContent(string label, string inputHtml, bool isCheckbox)
{ {
var content = isCheckbox ? var innerContent = isCheckbox ?
inputHtml + Environment.NewLine + label : inputHtml + Environment.NewLine + label :
label + Environment.NewLine + inputHtml; label + Environment.NewLine + inputHtml;
return "<div class=\"" + (isCheckbox ? "form-check" : "form-group") + "\">" + Environment.NewLine + content + Environment.NewLine + "</div>"; return "<div class=\"" + (isCheckbox ? "form-check" : "form-group") + "\">" + Environment.NewLine + innerContent + Environment.NewLine + "</div>";
} }
protected virtual TagHelperOutput GetInputTag(TagHelperContext context) protected virtual TagHelperOutput GetInputTag(TagHelperContext context)

31
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using Localization.Resources.AbpUi; using Localization.Resources.AbpUi;
@ -24,24 +25,34 @@ 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";
SetDivAttributes(output);
output.TagMode = TagMode.StartTagAndEndTag;
var selectTag = GetSelectTag(context); var selectTag = GetSelectTag(context);
var seelctAsHtml = RenderTagHelperOutput(selectTag, _encoder); var seelctAsHtml = RenderTagHelperOutput(selectTag, _encoder);
var labelAsHtml = GetLabelAsHtml(selectTag); var labelAsHtml = GetLabelAsHtml(selectTag);
var content = labelAsHtml + Environment.NewLine + seelctAsHtml; var content = GetContent(labelAsHtml,seelctAsHtml);
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 = order?.Number ?? 0
});
}
output.Content.SetHtmlContent(content); output.SuppressOutput();
} }
protected virtual void SetDivAttributes(TagHelperOutput output)
protected virtual string GetContent(string label, string inputHtml)
{ {
output.Attributes.RemoveAll("asp-for"); var innerContent = label + Environment.NewLine + inputHtml;
output.Attributes.RemoveAll("asp-items");
output.Attributes.Add("class", "form-group"); return "<div class=\"form-group\">" + Environment.NewLine + innerContent + Environment.NewLine + "</div>";
} }
protected virtual TagHelperOutput GetSelectTag(TagHelperContext context) protected virtual TagHelperOutput GetSelectTag(TagHelperContext context)

30
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/SelectItems.cs

@ -13,41 +13,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
public string ItemsListPropertyName { get; set; } public string ItemsListPropertyName { get; set; }
public Type EnumType { get; set; }
public SelectType SelectType { get; set; } = SelectType.Dropdown; public SelectType SelectType { get; set; } = SelectType.Dropdown;
public IEnumerable<SelectListItem> GetItems(ModelExplorer explorer) public IEnumerable<SelectListItem> GetItems(ModelExplorer explorer)
{ {
if (IsEnumItem()) var properties = explorer.Container.Properties.Where(p => p.Metadata.PropertyName.Equals(ItemsListPropertyName)).ToList();
{
return GetItemsFromEnum();
}
else
{
return GetItemsFromListField(explorer);
}
}
private IEnumerable<SelectListItem> GetItemsFromListField(ModelExplorer explorer)
{
var properties = explorer.Properties.Where(p => p.Metadata.PropertyName.Equals(ItemsListPropertyName)).ToList();
return properties.Count > 0 return properties.Count > 0
? properties.First().Model as IEnumerable<SelectListItem> ? properties.First().Model as IEnumerable<SelectListItem>
: new List<SelectListItem>(); : null;
}
private IEnumerable<SelectListItem> GetItemsFromEnum()
{
var enumItems = EnumType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static);
return enumItems.Select((t, i) => new SelectListItem() { Value = i.ToString(), Text = t.Name }).ToList();
}
private bool IsEnumItem()
{
return EnumType != null && EnumType.GetTypeInfo().IsEnum;
} }
} }
} }

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

@ -1,8 +1,9 @@
@page @page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
@model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.FormsModel @model FormsModel
@{ @{
ViewData["Title"] = "Forms"; ViewData["Title"] = "Forms";
} }
<h2>Forms</h2> <h2>Forms</h2>
@ -13,11 +14,8 @@
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">
<abp-dynamic-form model="@Model.Person"> <abp-dynamic-form asp-model="@Model.Ahmet">
<abp-input asp-for="@Model.Person.Name" />
<abp-input asp-for="@Model.Person.Age" />
<abp-input asp-for="@Model.Person.Phone.Number" />
</abp-dynamic-form> </abp-dynamic-form>
</div> </div>
<div class="code-area"> <div class="code-area">
@ -31,36 +29,36 @@
@*<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">
<form method="post" action="#"> <form method="post" action="#">
<abp-input asp-for="@Model.Name" /> <abp-input asp-for="@Model.Name" />
<abp-input asp-for="@Model.Password" label="Password" /> <abp-input asp-for="@Model.Password" label="Password" />
<abp-input asp-for="@Model.IsActive" /> <abp-input asp-for="@Model.IsActive" />
<abp-input asp-for="@Model.PhoneNumber" /> <abp-input asp-for="@Model.PhoneNumber" />
<abp-input asp-for="@Model.EmailAddress" /> <abp-input asp-for="@Model.EmailAddress" />
<abp-input asp-for="@Model.Count" /> <abp-input asp-for="@Model.Count" />
<abp-input asp-for="@Model.Day" /> <abp-input asp-for="@Model.Day" />
<abp-select asp-for="@Model.Country" asp-items="@Model.Countries" label="Country"></abp-select> <abp-select asp-for="@Model.Country" asp-items="@Model.Countries" label="Country"></abp-select>
<abp-select asp-for="@Model.City" asp-items="@Html.GetEnumSelectList(typeof(Cities))"></abp-select> <abp-select asp-for="@Model.City" asp-items="@Html.GetEnumSelectList(typeof(Cities))"></abp-select>
</form> </form>
</div> </div>
<div class="code-area"> <div class="code-area">
<pre> <pre>
&lt;form method=&quot;post&quot; action=&quot;#&quot;&gt; &lt;form method=&quot;post&quot; action=&quot;#&quot;&gt;
&lt;abp-input asp-for=&quot;Model.Name&quot;/&gt; &lt;abp-input asp-for=&quot;Model.Name&quot;/&gt;
&lt;abp-input asp-for=&quot;Model.Password&quot; label=&quot;Password&quot;/&gt; &lt;abp-input asp-for=&quot;Model.Password&quot; label=&quot;Password&quot;/&gt;
&lt;abp-input asp-for=&quot;Model.IsActive&quot; /&gt; &lt;abp-input asp-for=&quot;Model.IsActive&quot; /&gt;
&lt;abp-input asp-for=&quot;Model.PhoneNumber&quot; /&gt; &lt;abp-input asp-for=&quot;Model.PhoneNumber&quot; /&gt;
&lt;abp-input asp-for=&quot;Model.EmailAddress&quot; /&gt; &lt;abp-input asp-for=&quot;Model.EmailAddress&quot; /&gt;
&lt;abp-input asp-for=&quot;Model.Count&quot; /&gt; &lt;abp-input asp-for=&quot;Model.Count&quot; /&gt;
&lt;abp-input asp-for=&quot;Model.Day&quot; /&gt; &lt;abp-input asp-for=&quot;Model.Day&quot; /&gt;
&lt;abp-select asp-for=&quot;Model.Country&quot; asp-items=&quot;Model.Countries&quot; label=&quot;Country&quot;&gt;&lt;/abp-select&gt; &lt;abp-select asp-for=&quot;Model.Country&quot; asp-items=&quot;Model.Countries&quot; label=&quot;Country&quot;&gt;&lt;/abp-select&gt;
&lt;abp-select asp-for=&quot;Model.City&quot; asp-items=&quot;Html.GetEnumSelectList(typeof(Cities))&quot;&gt;&lt;/abp-select&gt; &lt;abp-select asp-for=&quot;Model.City&quot; asp-items=&quot;Html.GetEnumSelectList(typeof(Cities))&quot;&gt;&lt;/abp-select&gt;
&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">

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

@ -11,52 +11,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
{ {
public class FormsModel : PageModel public class FormsModel : PageModel
{ {
//[Required] public PersonViewModel Ahmet { get; set; } = new PersonViewModel();
//[DisplayName("Name")]
//public string Name { get; set; }
//[Required]
//[EmailAddress]
//[DisplayName("Email")]
//public string EmailAddress { get; set; }
//[DataType(DataType.Password)]
//public string Password { get; set; } = "MyPass";
//[Phone]
//[DisplayName("Phone Number")]
//[DisplayOrder(4)]
//public string PhoneNumber { get; set; }
//[DisplayName("Count")]
//public int Count { get; set; }
//[DataType(DataType.Date)]
//[DisplayName("Day")]
//public DateTime Day { get; set; }
//[DisplayName("Is Active")]
//public bool IsActive { get; set; }
//[DisplayName("Country")]
//public string Country { get; set; }
//[DisplayName("City")]
//public Cities City { get; set; }
public Person Person { get; set; }
public List<SelectListItem> Countries { get; } = new List<SelectListItem>
{
new SelectListItem { Value = "MX", Text = "Mexico" },
new SelectListItem { Value = "CA", Text = "Canada" },
new SelectListItem { Value = "US", Text = "USA" },
};
public static IEnumerable<SelectListItem> EnumCityList;
public void OnGet() public void OnGet()
{ {
Ahmet = new PersonViewModel
{
Name = "ahmet",
Age = 65,
Phone = new Phone {Number = "326346231",Name = "MyPhone"}
};
} }
} }
@ -67,11 +31,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
Moscow Moscow
} }
public class Person public class PersonViewModel
{ {
[Required] [Required]
[DisplayName("Name")] [DisplayName("Name")]
public string Name { get; set; } public string Name { get; set; } = "MyName";
[Required] [Required]
[DisplayOrder(61)] [DisplayOrder(61)]
@ -93,7 +57,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
public bool IsActive { get; set; } public bool IsActive { get; set; }
[DisplayName("Country")] [DisplayName("Country")]
[SelectItems(ItemsListPropertyName = nameof(Countries))]
public string Country { get; set; } public string Country { get; set; }
public List<SelectListItem> Countries { get; set; } = new List<SelectListItem>
{
new SelectListItem { Value = "MX", Text = "Mexico" },
new SelectListItem { Value = "CA", Text = "Canada" },
new SelectListItem { Value = "US", Text = "USA" },
};
} }
public class Phone public class Phone

Loading…
Cancel
Save