提交表单后重置文本区域的值

34
  1. 我想通过访问/MyController/Message/3向userID=3发送一条消息
  2. 这将执行Message() [get]操作,我在文本区域中输入一些文本,然后点击保存以发布表单
  3. Message() [post]操作保存更改,将SomeText的值重置为空字符串并返回到视图。

此时,我希望文本区域为空,因为我已经将ViewData["SomeText"]设置为string.Empty

为什么在提交操作后文本区域的值没有更新为空字符串?

以下是操作:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Message(int ID)
{
  ViewData["ID"] = ID;
  return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
  // save Text to database
  SaveToDB(ID, SomeText);

  // set the value of SomeText to empty and return to view
  ViewData["SomeText"] = string.Empty;
  return View();
}

相应的视图:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm()) 
   { %>
      <%= Html.Hidden("ID", ViewData["ID"])%>
      <label for="SomeText">SomeText:</label>
      <%= Html.TextArea("SomeText", ViewData["SomeText"]) %>
      <input type="submit" value="Save" />
<% } %>
</asp:Content>
9个回答

73

问题在于你的ModelState被重新填充了提交的值。

你可以在具有Post属性的Action上清除它:

ModelState.Clear();

2
这应该被标记为最佳答案。我必须将布尔值保留在ViewBag中,而RedirectToAction()函数会删除其中的数据。 - David

41
问题在于HtmlHelper正在检索填充了已发布数据的ModelState值。不要通过重置ModelState来解决此问题,而是重定向回[get]操作。[post] 操作还可以设置一个临时状态消息,如下所示:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
  // save Text to database
  SaveToDB(ID, SomeText);

  TempData["message"] = "Message sent";
  return RedirectToAction("Message");
}

这对我来说似乎是更正确的行为。


2
我认为这比仅清除ModelState更好。如果您正在进行发布,则实际上不需要更多的返回信息。如果您感觉需要返回完整的模型,则应该首先执行获取操作。还应该研究PRG模式;它可能会澄清一些问题。这也可能修复刷新时有时会出现的烦人浏览器消息,询问是否要重新发布表单的问题。 - Landon Poch
我正在做这件事,它在我的大多数表单上都有效,除了一些(可能是2或3个)。即使在提交并在Save(MyModel vm)的末尾使用RedirectToAction("save", new{ id = 0});之后,页面仍然从ModelState呈现值。除了ModelState.Clear()之外,我该怎么做才能在提交后重置表单? - phougatv
我找到了解决方案。Ajax.BeginFormUpdateTargetId提供了错误的Id - phougatv

7

HTML助手从ModelState中读取值。没有优雅的方法可以覆盖这种行为。

但是,如果在SaveToDB(ID, SomeText)之后添加此行代码,则应该可以正常工作:

ModelState["SomeText"].Value = 
    new ValueProviderResult("", "", CultureInfo.CurrentCulture);

1

我尝试了所有方法,但只有当我做类似于这样的事情时才起作用:

ModelState.Clear();
//This will clear the address that was submited
viewModel.Address = new Address();
viewModel.Message = "Dados salvos com sucesso!";
return View("Addresses", ReturnViewModel(viewModel));

希望这能帮到您。

ReturnViewModel是什么方法? - vapcguy
不记得 :D - MalachiteBR

1

如果你不想清除整个模型状态,可以使用ModelState.Remove("SomeText"),而不是使用ModelState.Clear()。或者可以渲染没有HTML助手扩展的输入框,这样它们就会从模型状态中获取值,而不是从模型(或视图数据)中获取值。


0

做类似这样的事情:

添加:

ModelState.Clear();

在提交按钮的操作方法的return语句之前。对我有效,它也可能对你有效。


0

模型状态是否可能已经更新了错误?我认为如果模型状态无效,它将从模型状态而不是视图数据或模型中提取尝试的值。

编辑: 我在下面包含了TextArea HtmlHelper扩展的源代码相关部分。在我的看法中,它确切地做到了我所期望的--如果存在模型错误,则从模型状态中提取该值,否则从ViewData中使用它。请注意,在您的Post方法中,“SomeText”键甚至在您设置它之前都不存在,即它不会从响应GET的代码版本中继承。

由于您明确向ViewData提供了一个值,因此useViewData应该为false,attemptedValue应该为false,除非在模型状态中设置了错误。

    // If there are any errors for a named field, we add the css attribute.
    ModelState modelState;
    if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) {
        if (modelState.Errors.Count > 0) {
            tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
        }
    }

    // The first newline is always trimmed when a TextArea is rendered, so we add an extra one
    // in case the value being rendered is something like "\r\nHello".
    // The attempted value receives precedence over the explicitly supplied value parameter.
    string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
    tagBuilder.SetInnerText(Environment.NewLine + (attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : value)));
    return tagBuilder.ToString(TagRenderMode.Normal);

我认为没有任何错误。我在另一个形式中遇到了同样的问题。我已经苦思冥想了几天,但是我找不出为什么会发生这种情况。当您无法控制提交后表单中出现的内容时,这非常令人恼火。我想知道是否有什么异常或错误的地方。 - xraminx

0

这是客户端行为。我建议使用JavaScript。如果您使用JQuery,可以像这样实现:

<script type="text/javascript">
$(function(){ $("#SomeText").val("");});
</script>

我不再使用JavaScript,但我相信在普通的JS中它是这样的:

document.getElementById("SomeText").value = "";

你可以在其中一个加载事件上执行此操作。

<body onload="...">

希望这能有所帮助。

我不这么认为。视图在推送到我的浏览器之前在服务器端呈现。 - xraminx
我同意,但我在考虑快速修复。不太确定为什么会这样返回。对我来说,在回传时一直都是这样的,以为这是一个特性。 - Jeff Ancel

0

我相当确定文本区域从Request.Form中获取值,因为ViewData["SomeText"]为空。


那么您是在建议正确的做法是以下方式吗?Request.Form["SomeMessage"] = string.Empty; - xraminx
不,Request.Form 不被 HtmlHelper 扩展使用。 - tvanfosson
我不会这么说。你可以将查询字符串参数命名为“title”,并将文本框命名为“title”,文本框将具有查询字符串的值。此外,它们还从Request.Form中获取其值,否则它如何在提交表单时获取值以填充表单或返回结果。 - Mike Geise

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接