2

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?

RajeshKdev
  • 6,365
  • 6
  • 58
  • 80

4 Answers4

1

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.

CharlieBrown
  • 4,143
  • 23
  • 24
0

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.

Community
  • 1
  • 1
Rowan Freeman
  • 15,724
  • 11
  • 69
  • 100
  • Hello Mr. Rowan, using session/cookies is my last resort, as much as possible, I really don't want to use session/cookies due to confidential information. – John Paulo Castro Mar 27 '14 at 05:51
0

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

Golda
  • 3,823
  • 10
  • 34
  • 67
  • Actually, I'm new to MVC4 razor and I don't really know how to use Ajax.BeginForm, but I'll try it. Thanks – John Paulo Castro Mar 27 '14 at 05:53
  • @JohnPauloCastro, Then check this video this will help you http://www.youtube.com/watch?v=B59skvlroyc – Golda Mar 27 '14 at 05:56
  • @JohnPauloCastro, Have you tried the video tutorial, have you added the required java script files? – Golda Mar 27 '14 at 06:03
  • I am currently downloading the video, I will look into it once finished. – John Paulo Castro Mar 27 '14 at 06:12
  • @JohnPauloCastro, Don't forgot to add "~/Scripts/jquery.unobtrusive-ajax.min.js" file. without this ajax won't work – Golda Mar 27 '14 at 06:14
  • hello again, it worked. but unfortunately, when I put a breakpoint into `[HttpPost]`, the web didn't stop at breakpoint. Another thing is, the `ViewBag.nextForm` didn't change the value, it stays as **CustomerType** instead of **Information** or **Service** – John Paulo Castro Mar 27 '14 at 06:27
  • @JohnPauloCastro, Have to set HttpMethod = "POST" in new AjaxOptions? You don't want to pass any viewBag. Instead you can return the partial view from the controller and update your div – Golda Mar 27 '14 at 06:52
  • I tried it and it worked, but it didn't meet my two requirements. 1. Only a single button will be clicked to navigate into different partial views. 2. When the action link clicked, the partial view is being loaded to new page, not into the target ID. – John Paulo Castro Mar 27 '14 at 07:33
  • @JohnPauloCastro, If the partial view is open in a new page means the ajax is not working. See the video it will load in the same page only. So that you can return the partial view from the controller – Golda Mar 27 '14 at 08:34
  • my partial view is in the same folder of views, I didn't put them to shared folder because the same folder is the only views that will use it. – John Paulo Castro Mar 27 '14 at 08:39
0

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

Sai Avinash
  • 4,683
  • 17
  • 58
  • 96
  • I can't use session because of confidential data and I am not good at handling session, and in regard to ajax calls, I tried but the ViewBag.nextForm's value stays the same. – John Paulo Castro Mar 27 '14 at 06:38