John Paulo Castro
John Paulo Castro

Reputation: 23

ASP.Net MVC4 Razor ViewBag

I am using a ViewBag as my checkpoint to which partial view should I render on a certain div and here's my code:

In Controller:

    [HttpPost]
    public ActionResult NewAppointment(appointment.AppointmentInformation model)
    {
        if (ViewBag.NextForm == null || ViewBag.NextForm == "undefined")
        {
            info.CustomerType = model.CustomerType;
            ViewBag.NextForm = "Information";
        }
        else if (ViewBag.NextForm == "Information")
        {
            info.CustomerID = String.IsNullOrEmpty(model.CustomerID) ? "" : model.CustomerID;
            info.CustomerName = String.IsNullOrEmpty(model.CustomerName) ? "" : model.CustomerName;
            info.CustomerCNum = String.IsNullOrEmpty(model.CustomerCNum) ? "" : model.CustomerCNum;
            ViewBag.NextForm = "Services";
        }
        else if (ViewBag.NextForm == "Services")
        {
            //do nothing;
        }
        return View(info);
    }

In View:

<form method="post">
<div id="PartialContainer">

    @if (ViewBag.NextForm == null || ViewBag.NextForm == "undefined")
    {
        @Html.Partial("CustomerType")
    }
    @if (ViewBag.NextForm == "Information")
    {
        @Html.Partial("GuestInformation")
    }
    @if (ViewBag.NextForm == "Services")
    {
        @Html.Partial("Service")
    }

</div>
<div id="ButtonArea">
    <button id="btnCancel">Cancel</button>
    <button id="btnBack">Back</button>
    <button id="btnNext">Next</button>
</div>

On third click of btnNext, the @Html.Part @Html.Partial("Service") is not working. But the first two @Html.Partial is working fine..

What's wrong with my code?

Upvotes: 2

Views: 15571

Answers (4)

CharlieBrown
CharlieBrown

Reputation: 4163

Why don't you embed the step in your form (in your partials)?

That way, whenever the form is submitted, you get which step it was, and show the proper next step from your controller code, not the view.

You could either add it as a property of your ViewModel, or simply just POST it and get it from Request object in your Controller.

Pseudo-code:

[HttpPost]
    public ActionResult NewAppointment(appointment.AppointmentInformation model)
    {
        //get the current step or start with empty string
        //although if this is the POST method, you should have the
        //first value, set in your GET method to show the form!
        var step = Request.Params["NextForm"] ?? "";

        if (step == "")
        {
            info.CustomerType = model.CustomerType;
            ViewBag.NextForm = "Information";
        }
        else if (step == "Information")
        {
            info.CustomerID = String.IsNullOrEmpty(model.CustomerID) ? "" : model.CustomerID;
            info.CustomerName = String.IsNullOrEmpty(model.CustomerName) ? "" : model.CustomerName;
            info.CustomerCNum = String.IsNullOrEmpty(model.CustomerCNum) ? "" : model.CustomerCNum;
            ViewBag.NextForm = "Services";
        }
        else if (step == "Services")
        {
            //do nothing;
        }
        return View(info);
    }

And then use that value in your View to have it sent anytime with your form.

<form method="post">
<div id="PartialContainer">
    <input type="hidden" name="NextForm" value="@(ViewBag.NextForm ?? "")" />

    @if (ViewBag.NextForm == null || ViewBag.NextForm == "undefined")
    {
        @Html.Partial("CustomerType")
    }
    @if (ViewBag.NextForm == "Information")
    {
        @Html.Partial("GuestInformation")
    }
    @if (ViewBag.NextForm == "Services")
    {
        @Html.Partial("Service")
    }

</div>
<div id="ButtonArea">
    <button id="btnCancel">Cancel</button>
    <button id="btnBack">Back</button>
    <button id="btnNext">Next</button>
</div>

You will be getting the NextStep with your form everytime, and then you just use ViewBag to pass data from controller to view, which is the intended use.

Hope it makes sense to you.

Upvotes: 1

Sai Avinash
Sai Avinash

Reputation: 4753

Yes, Indeed HTTP is a stateless protocol.

Your values will be lost between requests.

ASP.Net webforms uses ViewState to resolve this problem.

ASP.Net MVC does not support ViewState.

Why not put your data in session ? Or else you can make ajax calls that prevents entire page refresh

Upvotes: 0

Golda
Golda

Reputation: 3881

Why don't you using ajax for this

@using (Ajax.BeginForm("Action", "Controller", new AjaxOptions { HttpMethod = "POST",  UpdateTargetId = "PartialContainer" }))
{
}

The UpdateTargetId = "PartialContainer" will update your div with the partial view you have to return the partial view from the controller

Upvotes: 0

Rowan Freeman
Rowan Freeman

Reputation: 16348

HTTP is a stateless protocol. This means every request is new and any previous interaction between a client and a server is mostly "forgotten".

Every time the user makes a request, the ViewBag is reinitialised from scratch. It looks to me like your code assumes that the ViewBag "hangs around" in the client's browser until they make their next request. Unfortunately things don't work this way.

ViewBag.NextForm equalling "Services" will never take place because the application doesn't know where the user is at.

Maintaining state throughout an HTTP application is a long and ongoing discussion: How can I keep "state" information between calls to my CGI program? (1996?).

There is no single, obvious solution that I can give to you. One way is to hold information in the form as a hidden input and POST data back to your controller so that it knows where the user was. You can also hold information in cookies or the session.

Upvotes: 0

Related Questions