Browse Source

Form Tag helper improvements

pull/272/head
yekalkan 8 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>
{
[HtmlAttributeName("asp-model")]
public ModelExpression Model { get; set; }
[HtmlAttributeNotBound]
[ViewContext]

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

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Rendering;
@ -13,11 +14,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
private readonly HtmlEncoder _htmlEncoder;
private readonly AbpInputTagHelper _abpInputTagHelper;
private readonly AbpSelectTagHelper _abpSelectTagHelper;
public AbpDynamicFormTagHelperService(HtmlEncoder htmlEncoder, AbpInputTagHelper abpInputTagHelper)
public AbpDynamicFormTagHelperService(HtmlEncoder htmlEncoder, AbpInputTagHelper abpInputTagHelper, AbpSelectTagHelper abpSelectTagHelper)
{
_htmlEncoder = htmlEncoder;
_abpInputTagHelper = abpInputTagHelper;
_abpSelectTagHelper = abpSelectTagHelper;
}
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)
{
if (IsSelectGroup(context, model, out var selectItems))
{
ProcessSelectGroup(context, model, selectItems);
continue;
}
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)
@ -63,6 +77,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
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)
{
if (IsCsharpClassOrPrimitive(model.ModelType))
@ -71,6 +90,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return list;
}
if (IsListOfSelectItem(model.ModelType))
{
return list;
}
return model.Properties.Aggregate(list, ExploreModelsRecursively);
}
@ -78,13 +102,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var temp = explorer;
var propertyName = explorer.Metadata.PropertyName;
while (temp?.Container?.Metadata?.PropertyName != null)
{
temp = temp.Container;
propertyName = temp.Metadata.PropertyName + "." + propertyName;
}
return new ModelExpression(propertyName, explorer);
}
@ -94,17 +118,52 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
type.IsValueType ||
type == typeof(DateTime) ||
type == typeof(ValueType) ||
type == typeof(string) ||
type == typeof(decimal) ||
type == typeof(double) ||
type == typeof(String) ||
type == typeof(Decimal) ||
type == typeof(Double) ||
type == typeof(Guid) ||
type == typeof(Char) ||
type == typeof(Byte) ||
type == typeof(Boolean) ||
type == typeof(TimeSpan) ||
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(short) ||
type == typeof(int) ||
type == typeof(long) ||
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)
{
var content = isCheckbox ?
var innerContent = isCheckbox ?
inputHtml + Environment.NewLine + label :
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)

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

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Encodings.Web;
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)
{
output.TagName = "div";
SetDivAttributes(output);
output.TagMode = TagMode.StartTagAndEndTag;
var selectTag = GetSelectTag(context);
var seelctAsHtml = RenderTagHelperOutput(selectTag, _encoder);
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");
output.Attributes.RemoveAll("asp-items");
output.Attributes.Add("class", "form-group");
var innerContent = label + Environment.NewLine + inputHtml;
return "<div class=\"form-group\">" + Environment.NewLine + innerContent + Environment.NewLine + "</div>";
}
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 Type EnumType { get; set; }
public SelectType SelectType { get; set; } = SelectType.Dropdown;
public IEnumerable<SelectListItem> GetItems(ModelExplorer explorer)
{
if (IsEnumItem())
{
return GetItemsFromEnum();
}
else
{
return GetItemsFromListField(explorer);
}
}
private IEnumerable<SelectListItem> GetItemsFromListField(ModelExplorer explorer)
{
var properties = explorer.Properties.Where(p => p.Metadata.PropertyName.Equals(ItemsListPropertyName)).ToList();
var properties = explorer.Container.Properties.Where(p => p.Metadata.PropertyName.Equals(ItemsListPropertyName)).ToList();
return properties.Count > 0
? properties.First().Model as IEnumerable<SelectListItem>
: new List<SelectListItem>();
}
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;
: null;
}
}
}

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

@ -1,8 +1,9 @@
@page
@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>
@ -13,11 +14,8 @@
<div class="demo-with-code">
<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>
</div>
<div class="code-area">
@ -31,36 +29,36 @@
@*<h4># Input Group Example</h4>
<div class="demo-with-code">
<div class="demo-area">
<form method="post" action="#">
<abp-input asp-for="@Model.Name" />
<abp-input asp-for="@Model.Password" label="Password" />
<abp-input asp-for="@Model.IsActive" />
<abp-input asp-for="@Model.PhoneNumber" />
<abp-input asp-for="@Model.EmailAddress" />
<abp-input asp-for="@Model.Count" />
<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.City" asp-items="@Html.GetEnumSelectList(typeof(Cities))"></abp-select>
</form>
</div>
<div class="code-area">
<pre>
&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.Password&quot; label=&quot;Password&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.EmailAddress&quot; /&gt;
&lt;abp-input asp-for=&quot;Model.Count&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.City&quot; asp-items=&quot;Html.GetEnumSelectList(typeof(Cities))&quot;&gt;&lt;/abp-select&gt;
&lt;/form&gt;
</pre>
</div>
</div>*@
<div class="demo-with-code">
<div class="demo-area">
<form method="post" action="#">
<abp-input asp-for="@Model.Name" />
<abp-input asp-for="@Model.Password" label="Password" />
<abp-input asp-for="@Model.IsActive" />
<abp-input asp-for="@Model.PhoneNumber" />
<abp-input asp-for="@Model.EmailAddress" />
<abp-input asp-for="@Model.Count" />
<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.City" asp-items="@Html.GetEnumSelectList(typeof(Cities))"></abp-select>
</form>
</div>
<div class="code-area">
<pre>
&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.Password&quot; label=&quot;Password&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.EmailAddress&quot; /&gt;
&lt;abp-input asp-for=&quot;Model.Count&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.City&quot; asp-items=&quot;Html.GetEnumSelectList(typeof(Cities))&quot;&gt;&lt;/abp-select&gt;
&lt;/form&gt;
</pre>
</div>
</div>*@
@*<div class="demo-with-code">
<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
{
//[Required]
//[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 PersonViewModel Ahmet { get; set; } = new PersonViewModel();
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
}
public class Person
public class PersonViewModel
{
[Required]
[DisplayName("Name")]
public string Name { get; set; }
public string Name { get; set; } = "MyName";
[Required]
[DisplayOrder(61)]
@ -93,7 +57,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
public bool IsActive { get; set; }
[DisplayName("Country")]
[SelectItems(ItemsListPropertyName = nameof(Countries))]
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

Loading…
Cancel
Save