tags:

views:

1827

answers:

6
  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>
A: 

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);
tvanfosson
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
A: 

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.

Jeff Ancel
I don't think so. The view gets rendered on server side before being pushed to my browser.
xraminx
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
A: 

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

Mike Geise
So you are suggesting the correct way to do this is the following?Request.Form["SomeMessage"] = string.Empty;
xraminx
No -- the Request.Form is not used by the HtmlHelper extension.
tvanfosson
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
+2  A: 

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);
çağdaş
+4  A: 

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();
Olivier PAYEN
+2  A: 

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.

roryf