34
  1. I want to send a message to userID=3 by going to /MyController/Message/3
  2. This executes Message() [get] action, I enter some text in the text area and click on Save to post the form
  3. Message() [post] action saves the changes, resets the value of SomeText to empty string and returns to the view.

At this point I expect the text area to be empty because I have set ViewData["SomeText"] to string.Empty.

Why is text area value not updated to empty string after post action?

Here are the actions:

[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();
}

And the corresponding 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>
0

9 Answers 9

73

The problem is that your ModelState is re-filled with the posted values.

What you can do is clear it on the Action that has the Post attribute :

ModelState.Clear();
1
  • 2
    This should be flagged as the best answer. I had to keep a boolean value into the ViewBag and the RedirectToAction() function removes data from it.
    – David
    Commented May 8, 2014 at 20:25
41

The problem is the HtmlHelper is retrieving the ModelState value, which is filled with the posted data. Rather than hacking round this by resetting the ModelState, why not redirect back to the [get] action. The [post] action could also set a temporary status message like this:

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

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

This seems to me like more correct behaviour.

3
  • 2
    I do think this is better than just clearing the ModelState. If you are doing a post, then you really don't need more than just a message coming back. If you feel the need to return a full model, then you should probably be doing a get in the first place. Also look into the PRG pattern; it may clarify this a bit. This may also fix that annoying browser message that you can sometimes get when you refresh and it asks if you want to re-post a form. Commented Aug 26, 2013 at 18:34
  • I am doing exactly this, and it is working on most of my forms except a few(2 or 3 maybe). How come the page is still rendering the values from ModelState even after posting it and using RedirectToAction("save", new{ id = 0}); at the end of the Save(MyModel vm)? What can I do to reset the form after posting it other than ModelState.Clear()?
    – phougatv
    Commented Nov 20, 2016 at 9:07
  • I did found the solution. UpdateTargetId of Ajax.BeginForm was supplied with the incorrect Id.
    – phougatv
    Commented Nov 20, 2016 at 9:33
7

The html helpers read the value from the ModelState. And there's no elegant way to override this behaviour.

But if you add this line after SaveToDB(ID, SomeText), it should work :

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

I tried everything, but only worked when I did something like this:

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

Hope this helps.

2
  • ReturnViewModel? What method is this?
    – vapcguy
    Commented Oct 18, 2018 at 19:15
  • Don't remember :D Commented Sep 4, 2019 at 21:59
1

Instead of using ModelState.Clear() which clears the whole modelstate, you can do ModelState.Remove("SomeText"), if you want to. Or render the Input without the htmlhelper-extensions. They are designed to take the Value from ModelState instead of the Model (or viewdata).

0
0

That is a clientside behavior. I would recommend using javascript. If you use JQuery, you can do it like this:

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

I don't use Javascript anymore, but I believe in regular JS that it is like:

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

(You would do this on one of the load events.

<body onload="...">

Hope this helps.

2
  • I don't think so. The view gets rendered on server side before being pushed to my browser.
    – xraminx
    Commented Apr 25, 2009 at 0:28
  • I agree, but I was thinking quick fix. Not quite sure why it is coming back like that. It has always done so for me on a post back, thought it was a feature.
    – Jeff Ancel
    Commented Apr 25, 2009 at 3:56
0

I am fairly certain the textarea is grabbing the value from the Request.Form under the hood since ViewData["SomeText"] is empty.

3
  • So you are suggesting the correct way to do this is the following? Request.Form["SomeMessage"] = string.Empty;
    – xraminx
    Commented Apr 25, 2009 at 0:49
  • No -- the Request.Form is not used by the HtmlHelper extension.
    – tvanfosson
    Commented Apr 25, 2009 at 0:54
  • I would not say that. You can name a querystring parameter title and have your textbox with the name title and the TextBox will have the value of the querystring. Also they do pull thier values from the Request.Form, how else would it get the values to populate the form or return the results when the form is posted.
    – Mike Geise
    Commented Apr 25, 2009 at 1:01
0

Is it possible that the model state has been updated with an error? I believe that it will pull the attempted value from the model state rather than from view data or the model if the model state isn't valid.

EDIT: I'm including the relevant section of the source code from the TextArea HtmlHelper extension below. It appears to me that it does exactly what I expected -- if there has been a model error, it pulls the value from the model state, otherwise it uses it from ViewData. Note that in your Post method the "SomeText" key shouldn't even exist until you set it, i.e., it won't be carried forward from the version of the code that responds to the GET.

Since you explicitly supply a value to the ViewData, useViewData should be false, attemptedValue should be false unless an error has been set in the model state.

    // 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);
1
  • I don't think there were any errors. I have had the same problem in another form. I have been scratching my head for a few days now but I could not find why this is happening. It's quite annoying when you have no control on what appears in your form after the post action. I was wondering if I am doing anything unusual or wrong.
    – xraminx
    Commented Apr 25, 2009 at 0:25
0

Do s.th. like this:

add:

ModelState.Clear();

before the return statement of the submit buttons action method. Works for me. It could work for you.

Not the answer you're looking for? Browse other questions tagged or ask your own question.