asp.net-mvc-4partial-viewsmodelstatemodel-validationstrongly-typed-view

ASP .NET MVC 4 View containing two partial Views with a form in each


In my MVC 4 application I have an Index View. In this View I have two div tags where a Partial view is rendered. There are two buttons that when clicked toggles between these two divs using jQuery. The Partial Views are strongly typed with its model each.

Question:

How do I pass the models to the partial views? How do I handle POST requests from the Partial views? In the POST action method(s) if ModelState is invalid how do I re-render the view that is aware of the ModelStae?

Is Partial views the way to go in this scenario? Are there better ways to achieve this with MVC 4?

Any help is appreciated.

Here is what I've tried without any success:

Index.cshtml

<div id="token">
   <!-- insert Token based PartialView -->
@{
    //Html.RenderPartial("_TokenPartial");
    Html.RenderAction("TokenBased");
}

<div id="credentials">
  <!-- insert Credentials based PartialView -->
@{
   //Html.RenderPartial("_CredentialPartial");
   Html.RenderAction("CredentialsBased");
}
</div>

I tried with HTML.RenderPartial("_partial") but couldn't specify the the model the partial View is based on. Then I tried with Html.RenderAction("TokenBased") and in this action returns the partial view with an instance of the model for this View:

CredentialController.cs

    public ActionResult TokenBased(string token)
    {
        ...

        return View("_TokenPartial", new TokenModel);
    }

And here is the partial View:

TokenPartial.cshtml

    @model TokenModel

    @using (Html.BeginForm("CreateAgreementToken", "Credential"))
    {
        <div class="formscontent">
            @Html.LabelFor(x => x.Token) <br />
            @Html.TextBoxFor(x => x.Token, new {size = "44" })
            @Html.ValidationMessageFor(x => x.Token)
            <br />
            <br />

            @Html.LabelFor(x => x.Email) <br />
            @Html.TextBoxFor(x => x.Email, new {size = "30" })
            @Html.ValidationMessageFor(x => x.Email)
            <br />
            <br />

            @Html.CheckBoxFor(x => x.AcceptSubsTerms, new { value = "SubsTerms"})
            @Html.LabelFor(x => x.AcceptSubsTerms)
            @Html.ValidationMessageFor(x => x.AcceptSubsTerms)
            @Html.ActionLink("SubsTermsLinkText", "Subscription", null, new {target = "_blank"})
            <br />
            <br />
        </div>
        <br />

        <input class="mainbutton" type="submit" value="CreateAgreement_btn_txt"/><br />

    }

And here is the POST action method:

    [HttpPost]
    public ActionResult CreateAgreementToken(TokenModel model)
    {

        if (ModelState.IsValid)
        {
            // Create Agreement
            //
            //

            return RedirectToAction("Welcome");
        }

        // If we got this far, something failed, redisplay form
        ModelState.AddModelError("", "The user credentials provided are incorrect.");

        // Where to redirect to.
        // How to re-render the Index view that's aware of the ModelState errors

        return RedirectToAction("Index");
    }

How to handle the interactions between the Controller action methods, the Index View and the Partial View like in the 'normal' case where you have an Index action method rendering an Index View passing it a model instance. And then in the Index POST action method if validation fails, you redisplay the form by calling the Index view passing it the invalid model.

Thank you


Solution

  • To pass a model to a partial you do it using @Html.Partial("SomeFile", SomeModel);

    I would recommend if you have multiple forms that you give them each different controller actions. You can specify the controller and action paramters using @Html.BeginForm.

    Partials are just a way of organizing the html. They have no context once the page is rendered so I wouldn't be too concerned about that.

    In order for your view to know about the errors in your model state you need to pass it the model. Instead of redirecting to index return the Index view and pass in your model as the second parameter.