ASP.Net MVC 动态输入绑定到同一控制器 属性

ASP.Net MVC Dynamic input bound to same controller property

我有 2 个控制器字段,分别是类型和数据。 根据为类型(日期或文本)选择的值,我想将数据字段动态显示为文本输入或自定义时间选择器输入。 由于任何时候只会渲染一个,因此我需要使用相同的 属性 名称(数据)进行绑定。 这就是我正在尝试的:

@if (Model.Type == "Date")
{
   // custom timepicker control goes here
   <input asp-for="Data" class="form-control timepicker"/>
}
else
{
   <input asp-for="Data" class="form-control text-input" type="text"/>
}

在页面加载时仅呈现文本输入,并且它 shows/hides 基于所选的类型。 timepicker 输入永远不会显示(根本不会生成 html)。

有没有办法在 MVC 中实现这一点?

不能有两个同名的 <input> 元素。如果发布包含多个同名输入的 <form>,则 MVC 模型绑定器将仅绑定最后一个输入中的一个值。

要实现你想要的,你有两个选择:

  • 要么在视图中只有一个输入 name="Data"type="text",然后让时间选择器将时间作为字符串写入此输入。然后在控制器中,根据选择的 Type.

  • 解析这个输入值
  • 或者有两个输入 name="TextData"name="TimeData",并根据所选 Type 使用 JS 禁用和隐藏其中一个输入。在控制器中,根据所选 Type 从右侧输入读取值。这可以说是更清洁的解决方案。

在 MVC5 中,第二种解决方案如下所示(我不熟悉 MVC-Core):

@model MyViewModel
@using (Html.BeginForm("Submit", "MyController", FormMethod.Post)) {
    @Html.EditorFor(m => m.Type)
    @Html.EditorFor(m => m.TextData, new { @class = "text-input"})
    @Html.EditorFor(m => m.TimeData, new { @class = "timepicker"})
}

<script type="text/javascript">
    function toggleInput_() {
         if ($('#@Html.IdFor(m => m.Type)').val() === 'Text') {
             $('#@Html.IdFor(m => m.TextData)').prop('disabled', false).show();
             $('#@Html.IdFor(m => m.TimeData)').prop('disabled', true).hide();
         }
         else {
             $('#@Html.IdFor(m => m.TextData)').prop('disabled', true).hide();
             $('#@Html.IdFor(m => m.TimeData)').prop('disabled', false).show();
         }
    }

    $(document).ready(function() {
        $('#@Html.IdFor(m => m.Type)').on('change', function() {
            toggleInput_(); // toggle when drop down changes
        });

        toggleInput_(); // toggle initially on page load
    });
</script>

控制器:

[HttPost]
public ActionResult Submit(MyViewModel postData) {

    string textValue = null;
    DateTime? timeValue = null;

    if (postData.Type == "Text") {
        textValue = postData.TextData;
    }
    else {
        timeValue = postData.TimeData;
    }

    // ...
}

ASP MVC 已经通过 编辑器模板 内置了此功能。按照约定,您可以指定一个模板用于将使用 @Html.EditorFor().

呈现的任何类型(包括用户定义的复杂类型)

简而言之,只需将两个局部视图放在 ~/Views/Shared/EditorTemplates 文件夹中,一个模型类型为 DateTime,另一个为 string。根据 Property.

的类型使用 @Html.EditorFor(m => m.Property) 时将呈现正确的局部视图

注意:string 属性 的默认编辑器已经是 type="text" 的输入,因此您不一定需要指定该模板.

有关编辑器模板(和显示模板)的教程,请参阅此 link: https://exceptionnotfound.net/asp-net-mvc-demystified-display-and-editor-templates/