Validation messages are displayed when page load
Asked Answered
S

4

12

I have a problem with validation in ASP.NET MVC 2.0. I use the same Action in Controller to perform user request.
For example:

public ActionResult Index(ReportModel model)
{
    if (!model.IsInitialDisplay && ModelState.IsValid)
    {
        model.Result = service.GetResult(model);                
    }
    return View(model);
}  

In the ReportModel, I define a flag IsInitialDisplay to determine whether the page is initial displayed or not:

public class ReportModel
{
    [Required(ErrorMessage = "*")]
    public string Criteria { get; set; }
    public bool IsInitialDisplay { get; set; }
    public ReportResult Result { get; set; }

    public ReportModel()
    {
        IsInitialDisplay = true;
    }
}  

And in the View, I use the following code:

<% using (Html.BeginForm())
   { %>
<table>
    <tr>
        <th>
            Criteria:
        </th>
        <td>
            <%= Html.TextBox("Criteria", "") %>
            <%= Html.ValidationMessage("Criteria") %>
        </td>
    </tr>
</table>
<br />
<input type="submit" value="Submit" />
<%= Html.Hidden("IsInitialDisplay", false) %>
<% } %>  

As I expect, if users don't input any value for Criteria and click Submit button, the error message for validation will be displayed.
But the validation error message always displayed on initial page load, I don't know how to prevent it?
Does anyone know? Thanks,

[Updated]
I have updated my Action method as below and it's seem to be fine:

public ActionResult Index(ReportModel model)
{
    // Collecting some commons data here...

    if (model.IsInitialDisplay)
    {
        ModelState.Clear();
    }
    else if (ModelState.IsValid)
    {
        model.Result = service.GetResult(model);                
    }
    return View(model);
}
Stockist answered 18/3, 2011 at 3:42 Comment(0)
T
38

The reason an error message is displayed on initial page load is because your controller action takes ReportModel model as argument. When you first access this action with /Home/Index you are passing no arguments and when the default model binder tries to bind to a ReportModel instance it triggers validation errors.

It is a bad practice to use the same action for both rendering and handling the form submission but if you really want to do it you could try like this:

public ActionResult Index(bool? isInitialDisplay)
{
    if (isInitialDisplay.HasValue && !isInitialDisplay.Value)
    {
        var model = new ReportModel();
        UpdateModel(model);
        if (ModelState.IsValid)
        {
            model.Result = service.GetResult(model);                
        }
        return View(model);
    }

    // Initial request
    return View(new ReportModel());
}

In this case you no longer need the IsInitialDisplay property on your model nor the constructor which sets it to true.

This being said, here's the recommended way:

public ActionResult Index()
{
    var model = new ReportModel();
    return View(model);
}

[HttpPost]
public ActionResult Index(ReportModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    model.Result = service.GetResult(model);                
    return View(model);
}
Tanager answered 18/3, 2011 at 8:59 Comment(5)
Thanks for your suggestion, but in my project, I need to collect some commons data for ReportModel.Criteria. So, I don't want to duplicate these business logic in both two actions (with & without model).Stockist
this is curious to me as I am getting this error for the reason you described but the Action is accepting a model because it is part of a series of forms and was POSTed to, and then the actual page posts to the next one... so I am not sure why it would be a bad practiceSwanner
Why is it a bad practise to "use the same action for both rendering and handling the form"? What's wrong?Savate
@Savate see the very question this answer was posted to, that is one example of a complication that arises when you try to multitask with a single controller action.Firebug
I'm wondering why this answer was NOT marked as answer. This is was very helpful for me. Thanks :)Fulllength
P
7

Here's a simple solution that combines some good answers:

[HttpGet]
public ActionResult Index(ReportsModel model)
{
    ModelState.Clear(); //clears the validation

    return View(model);
}

[HttpPost]
public ActionResult Index(ReportsModel model, string unused)
{
    ...
}

This uses the http method to determine if it's first load (like Darin's solution).

Most importantly, it has MVC build your controller instead of manually newing one up yourself. This is important if you use dependency injection or if you had other contextual data coming in through the query string (like a nested resource id).

Pamphleteer answered 1/8, 2012 at 15:56 Comment(0)
Z
0

Model

public class ReportModel
{
     [Required(ErrorMessage = "*")]
     public string Criteria { get; set; }
}

View

<% Html.EnableClientValidation(); %>    

<% using (Html.BeginForm())
{ %>
     <%= Html.TextBoxFor(model => model.Criteria) %>
     <%= Html.ValidationMessageFor(model => model.Criteria) %>

     <input type="submit" value="Submit" />
<% } %>  

Work fine

Zither answered 18/3, 2011 at 8:59 Comment(1)
In my project, I use complex model object for ReportModel.Criteria. So, your suggestion is not suitable.Stockist
C
0

If you need to handle form submission with the same action name, you should always use this technique:

[HttpGet]
public ActionResult Index()
{
    /* Just returning the view. No validation will happen because we are not passing a parameter*/
    return View();
}

[HttpPost]
public ActionResult Index(ReportsModel model)
{
    //Another post action for validation
}
Corybantic answered 16/4, 2020 at 11:13 Comment(1)
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.Winshell

© 2022 - 2024 — McMap. All rights reserved.