【问题标题】:Creating dynamic forms with .net.core使用 .net.core 创建动态表单
【发布时间】:2021-06-04 02:41:43
【问题描述】:

我需要为不同的客户端提供不同的表单,这些表单都可以在后台配置(最终在数据库中)

我最初的想法是为“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);
    }

在视图中,我为每个 FormItems 调用 HtmlHelper

@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);
    }

由于属性(例如 RegExAttribute 的RequiredAttribute)不存在,因此验证也将不起作用。

我的方法有误,还是有更明确的方法来完成这样的表格?

有没有一种方法可以创建一个动态的 ViewModel,它可以从原始设置中创建并仍然保留所有 MVC 的丰富性?

【问题讨论】:

  • 你找到解决方案了吗?
  • @Bonner웃 如果您在下面查看,mcintyre321 对此进行了回复。但是,当我移动项目时,我没有进一步研究这个问题。查看aspdatatables.azurewebsites.net 的演示,它似乎做了我想要的事情,但我的示例要复杂得多,可能有 100 个字段。
  • 我不喜欢 FormFactory 解决方案,因为模型被传递到解析器中,而且感觉非常有限。我更喜欢 WebForms API 而不是 FormFactory 库,这就是我问的原因。
  • 我也遇到过这个问题。我知道你已经离开了这个项目,但只是在这里碰碰运气,你或@BrownCow 找到了不同的解决方案吗?
  • @learner 不,我继续前进:)

标签: asp.net-mvc forms model-view-controller custom-model-binder


【解决方案1】:

您可以使用我的 FormFactory 库来做到这一点。

默认情况下,它会根据视图模型反射以生成 PropertyVm[] 数组:

```

var vm = new MyFormViewModel
{
    OperatingSystem = "IOS",
    OperatingSystem_choices = new[]{"IOS", "Android",};
};
Html.PropertiesFor(vm).Render(Html);

```

但您也可以通过编程方式创建属性,因此您可以从数据库加载设置然后创建PropertyVm

这是来自 Linqpad 脚本的 sn-p。

```

//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.
}

```

demo site 提供了您可以设置的各种功能的示例(例如嵌套集合、自动完成、日期选择器等)

【讨论】:

    【解决方案2】:

    我将把我的解决方案放在这里,因为我发现这个搜索“如何在 mvc 核心中创建动态表单”。我不想使用 3rd 方库。

    型号:

    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>
    

    【讨论】:

    • 这是我的一个旧帖子,这是否包含验证?
    • 我不明白为什么它不会。我不确定剃须刀标签。我从朋友那里得到的代码已经用旧的 mvc 代码验证了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 2021-04-17
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    相关资源
    最近更新 更多