Создание динамических форм с помощью.net.core
У меня есть требование иметь разные формы для разных клиентов, которые могут быть настроены в фоновом режиме (в конце концов, в базе данных)
Моя первоначальная идея состоит в том, чтобы создать объект для "Form", который имеет "Словарь FormItem" для описания полей формы.
Затем я могу создать новую динамическую форму, выполнив следующее (это будет из базы данных / службы):
private Form GetFormData()
{
var dict = new Dictionary<string, FormItem>();
dict.Add("FirstName", new FormItem()
{
FieldType = Core.Web.FieldType.TextBox,
FieldName = "FirstName",
Label = "FieldFirstNameLabel",
Value = "FName"
});
dict.Add("LastName", new FormItem()
{
FieldType = Core.Web.FieldType.TextBox,
FieldName = "LastName",
Label = "FieldLastNameLabel",
Value = "LName"
});
dict.Add("Submit", new FormItem()
{
FieldType = Core.Web.FieldType.Submit,
FieldName = "Submit",
Label = null,
Value = "Submit"
});
var form = new Form()
{
Method = "Post",
Action = "Index",
FormItems = dict
};
return form;
}
Внутри моего контроллера я могу получить данные формы и передать их в представление
public IActionResult Index()
{
var formSetup = GetFormData(); // This will call into the service and get the form and the values
return View(formSetup);
}
Внутри представления я вызываю HtmlHelper для каждого из FormItems
@model Form
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using FormsSpike.Core.Web
@{
ViewData["Title"] = "Home Page";
}
@using (Html.BeginForm(Model.Action, "Home", FormMethod.Post))
{
foreach (var item in Model.FormItems)
{
@Html.FieldFor(item);
}
}
Затем при повторной публикации мне приходится перебирать переменные формы и сопоставлять их снова. Это кажется очень старой школой, которую я ожидал бы сделать в каком-то модельном переплете.
[HttpPost]
public IActionResult Index(IFormCollection form)
{
var formSetup = GetFormData();
foreach (var formitem in form)
{
var submittedformItem = formitem;
if (formSetup.FormItems.Any(w => w.Key == submittedformItem.Key))
{
FormItem formItemTemp = formSetup.FormItems.Single(w => w.Key == submittedformItem.Key).Value;
formItemTemp.Value = submittedformItem.Value;
}
}
return View("Index", formSetup);
}
Это я могу затем выполнить некоторые сопоставления, которые будут обновлять базу данных в фоновом режиме.
Моя проблема в том, что это просто неправильно:o{
Также я использовал очень простой HtmlHelper, но я не могу использовать стандартные htmlHelpers (такие как LabelFor) для создания форм, так как нет модели для привязки к..
public static HtmlString FieldFor(this IHtmlHelper html, KeyValuePair<string, FormItem> item)
{
string stringformat = "";
switch (item.Value.FieldType)
{
case FieldType.TextBox:
stringformat = $"<div class='formItem'><label for='item.Key'>{item.Value.Label}</label><input type='text' id='{item.Key}' name='{item.Key}' value='{item.Value.Value}' /></ div >";
break;
case FieldType.Number:
stringformat = $"<div class='formItem'><label for='item.Key'>{item.Value.Label}</label><input type='number' id='{item.Key}' name='{item.Key}' value='{item.Value.Value}' /></ div >";
break;
case FieldType.Submit:
stringformat = $"<input type='submit' name='{item.Key}' value='{item.Value.Value}'>";
break;
default:
break;
}
return new HtmlString(stringformat);
}
Также проверка не будет работать, поскольку атрибуты (например, RequiredAttribute для RegExAttribute) отсутствуют.
У меня неправильный подход к этому или есть более определенный способ заполнить формы, подобные этой?
Есть ли способ создать динамическую ViewModel, которая может быть создана из первоначальной настройки и при этом сохранить все богатство MVC?
3 ответа
Вы можете сделать это, используя мою библиотеку FormFactory.
По умолчанию он отражает модель представления для создания PropertyVm[]
массив:
`` `
var vm = new MyFormViewModel
{
OperatingSystem = "IOS",
OperatingSystem_choices = new[]{"IOS", "Android",};
};
Html.PropertiesFor(vm).Render(Html);
`` `
но вы также можете создавать свойства программно, чтобы вы могли загрузить настройки из базы данных, а затем создать PropertyVm
,
Это фрагмент из скрипта Linqpad.
`` `
//import-package FormFactory
//import-package FormFactory.RazorGenerator
void Main()
{
var properties = new[]{
new PropertyVm(typeof(string), "username"){
DisplayName = "Username",
NotOptional = true,
},
new PropertyVm(typeof(string), "password"){
DisplayName = "Password",
NotOptional = true,
GetCustomAttributes = () => new object[]{ new DataTypeAttribute(DataType.Password) }
}
};
var html = FormFactory.RazorEngine.PropertyRenderExtension.Render(properties, new FormFactory.RazorEngine.RazorTemplateHtmlHelper());
Util.RawHtml(html.ToEncodedString()).Dump(); //Renders html for a username and password field.
}
`` `
Это демонстрационный сайт с примерами различных функций, которые вы можете настроить (например, вложенные коллекции, автозаполнение, средства выбора даты и т. Д.)
Я собираюсь разместить здесь свое решение, так как я нашел этот поиск «как создать динамическую форму в ядре mvc». Я не хотел использовать стороннюю библиотеку.
Модель:
public class IndexViewModel
{
public Dictionary<int, DetailTemplateItem> FormBody { get; set; }
public string EmailAddress { get; set; }
public string templateName { get; set; }
}
cshtml
<form asp-action="ProcessResultsDetails" asp-controller="home" method="post">
<div class="form-group">
<label asp-for=@Model.EmailAddress class="control-label"></label>
<input asp-for=@Model.EmailAddress class="form-control" />
</div>
@foreach (var key in Model.FormBody.Keys)
{
<div class="form-group">
<label asp-for="@Model.FormBody[key].Name" class="control-label">@Model.FormBody[key].Name</label>
<input asp-for="@Model.FormBody[key].Value" class="form-control" value="@Model.FormBody[key].Value"/>
<input type="hidden" asp-for="@Model.FormBody[key].Name"/>
</div>
}
<input type="hidden" asp-for="templateName" />
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
Вы можете использовать JJMasterData, он может создавать динамические формы из ваших таблиц во время выполнения или во время компиляции. Поддерживает как .NET 6, так и .NET Framework 4.8.
- После настройки пакета откройте /en-us/DataDictionary в своем браузере.
- Создайте словарь данных, добавив имя таблицы
- Нажмите «Дополнительно», «Получить сценарии», «Выполнить хранимые процедуры», а затем нажмите «Предварительный просмотр» и проверьте.
- Чтобы использовать CRUD во время выполнения, перейдите по адресу en-us/MasterData/Form/Render/{YOUR_DICTIONARY}.
- Чтобы использовать CRUD на определенной странице или настроить во время компиляции, следуйте приведенному ниже примеру:
На вашем контроллере:
public IActionResult Index(string dictionaryName)
{
var form = new JJFormView("YourDataDictionary");
form.FormElement.Title = "Example of compile time customization"
var runtimeField = new FormElementField();
runtimeField.Label = "Field Label";
runtimeField.Name = "FieldName";
runtimeField.DataType = FieldType.Text;
runtimeField.VisibleExpression = "exp:{pagestate}='INSERT'";
runtimeField.Component = FormComponent.Text;
runtimeField.DataBehavior = FieldBehavior.Virtual; //Virtual means the field does not exist in the database.
runtimeField.CssClass = "col-sm-4";
form.FormElement.Fields.Add(runtimeField);
return View(form);
}
На ваш взгляд:
@using JJMasterData.Web.Extensions
@model JJFormView
@using (Html.BeginForm())
{
@Model.GetHtmlString()
}