post中未修改的视图模型值未显示在DropDownListFor中

时间:2014-07-14 16:18:56

标签: asp.net-mvc asp.net-mvc-4

我尝试使用静态HTML实现添加和删除行的按钮。我看到this question似乎是我想要的,但我发现该示例不适用于下拉列表。没有下拉列表'任何选项都标记为已选中。如果我不清除模型状态,则保留所有旧值。如何保持对视图模型的更改?

// Controller action
[HttpPost]
public virtual ActionResult DoSomething(DoSomethingViewModel viewModel)
{
    if (viewModel != null)
    {
        if (viewModel.ButtonPressed != null)
        {
            if (viewModel.ButtonPressed.Trim() == "Cancel")
            {
                return Redirect(ApplicationUtilities.CancelRequestUrl);
            }
            else if (viewModel.ButtonPressed.Trim() == "AddRow")
            {
                ModelState.Clear();

                // This only covers non-JavaScript users.

                // One for the newest one.
                viewModel.FieldOneValues.Add(String.Empty);
                viewModel.FieldTwoValues.Add(String.Empty);
                viewModel.FieldThreeValues.Add(null);

                return View(viewModel);
            }
            else if (viewModel.ButtonPressed.Trim().StartsWith("Remove"))
            {
                ModelState.Clear();
                String[] split = viewModel.ButtonPressed.Split('-');
                if (split.Length == 2)
                {
                    Int32 indexToRemove;
                    Regex regex = new Regex(@"\[([0-9]+)\]");
                    Match match = regex.Match(split[1]);
                    if (match.Success && Int32.TryParse(match.Groups[1].Value, out indexToRemove))
                    {
                        viewModel.FieldOneValues.RemoveAt(indexToRemove);
                        viewModel.FieldTwoValues.RemoveAt(indexToRemove);
                        viewModel.FieldThreeValues.RemoveAt(indexToRemove);
                    }
                }

                return View(viewModel);
            }
        }
    }

    if (ModelState.IsValid)
    {
        return WhateverIsDoneOnSuccess(viewModel);
    }
    else
    {
        return View(viewModel);
    }
}

// View Model
public class DoSomethingViewModel
{
    public DoSomethingViewModel()
    {
        this.FieldOneValues = new List<String>();
        this.FieldTwoValues = new List<String>();
        this.FieldThreeValues = new List<Int32?>();
    }

    public virtual IList<String> FieldOneValues { get; set; }
    public virtual IList<String> FieldTwoValues { get; set; }
    public virtual IList<Int32?> FieldThreeValues { get; set; }
    public virtual String ButtonPressed { get; set; }
}

<!-- Spark View -->
<tr each="var fieldOneValue in Model.FieldOneValues">
    <td headers="FieldOneTh">${Html.TextAreaFor(m => m.FieldOneValues[fieldOneValueIndex])}</td>
    <td headers="FieldTwoTh">${Html.TextAreaFor(m => m.FieldTwoValues[fieldOneValueIndex])}</td>
    <td headers="FieldThreeTh">
        ${Html.TextBoxFor(m => m.fieldOneValueIndex], new { disabled="disabled", @readonly="readonly" })}
        ${Html.DropDownListFor(
            m => m.FieldThreeValues[fieldOneValueIndex]
          , ApplicationUtilities.FieldThreeSelectListItems
          , " "
        )}
    </td>
    <td headers="AddRemoveTh">
        <button name="${Html.NameFor(m => m.ButtonPressed)}" class="Remove" type="submit" value="Remove-[${fieldOneValueIndex}]">Remove</button>
        <button if="fieldOneValueIsLast" name="${Html.NameFor(m => m.ButtonPressed)}" class="Add" type="submit" value="AddRow">Add</button>
    </td>
</tr>

<!-- HTML Output -->
<tr>
    <td headers="FieldOneTh"><textarea cols="20" id="FieldOneValues_0_" name="FieldOneValues[0]" rows="2">
</textarea></td>
    <td headers="FieldTwoTh"><textarea cols="20" id="FieldTwoValues_0_" name="FieldTwoValues[0]" rows="2">
</textarea></td>
    <td headers="FieldThreeTh">
        <input data-val="true" data-val-number="The field Nullable`1 must be a number." disabled="disabled" id="FieldThreeValues_0_" name="FieldThreeValues[0]" readonly="readonly" type="text" value="0" />
        <select id="FieldThreeValues_0_" name="FieldThreeValues[0]"><option value=""> </option>
<option value="0">Option 1</option>
<option value="1">Option 2</option>
<option value="2">Option 3option>
</select>
    </td>
    <td headers="AddRemoveTh">
        <button name="ButtonPressed" class="Remove" type="submit" value="Remove-[0]">Remove</button>
        <button name="ButtonPressed" class="Add" type="submit" value="AddRow">Add</button>
    </td>
</tr>

1 个答案:

答案 0 :(得分:2)

  

另外,我很好奇;我认为应该有办法做到这一点。

有,但你必须正确处理帖子。在这种情况下,为什么建议使用PRG(Post-Redirect-Get)。当您单击特定项目的删除按钮之类的内容时,保存所有其他字段并执行实际提交整个表单时会发生的任何其他操作都不合适。所有用户都表示他们想删除这一项。

因此,当您收到帖子时,您会从数据库中删除该项目,或者将其保留在任何位置,然后将重定向重新定位到原始表单中,如果这是您的内容想。重定向过程更新页面状态,以便项目现在消失,然后可以编辑表单的其余部分,而无需携带陈旧数据。您尝试执行的操作是删除该项目,然后直接返回视图,该视图仍然包含支持它的数据中的已发布项目。这就是问题所在。

我认为你走的是这条路,因为你试图维护用户对表单其他区域所做的任何编辑,但这根本不可能。但是,您有一些选择:

  1. 实际上没有一个按钮可以在这一分钟内删除该项目。相反,提供一个复选框或指示当用户发布整个表单时应删除该项目的内容。然后,您可以保存所有表单数据,删除指定的项目,然后重新定向,就像您应该的那样。

  2. 使用本地存储在客户端保存用户的编辑,然后在重定向后再次加载页面后从本地存储中读取它们。但是,这需要JS。

  3. 使用AJAX提交删除项目的请求,然后从DOM中删除该行。但是,这需要JS。

  4. 另外,请记住,完全有可能逐步增强您的表单。所以,你可以实现#1 #3,然后如果JS不可用,#1仍然可以作为后备。