JabberwockyDecompiler
JabberwockyDecompiler

Reputation: 3390

MVC Wizard Issues

I am attempting to create a wizard in MVC. Because I need to submit stuff to the DB after each step, I am would like to pass the data back to the controller instead of handling this client side. I cannot for the life of me figure out what I am doing wrong though. I have a containing ViewModel with the ViewModels for each of the steps and a StepIndex to keep track of where I am at. Each of the step pages are strongly typed to the containing ViewModel. For some reason when I increment the StepIndex it shows that it is incremented in the controller, but it is never kept. I have a hidden value for it, and the Step1 value is passed. I have tried model.StepIndex++ and model.StepIndex + 1, both show in the controller as incremented but when the view is loaded the incorrect value is used. I even turned off caching to see if that was the cause. Please let me know if you see what I am doing wrong. Thank You, TJ

Containing View Model

public class WizardVM
{
    public WizardVM()
    {
        Step1 = new Step1VM();
        Step2 = new Step2VM();
        Step3 = new Step3VM();
    }

    public Step1VM Step1 { get; set; }
    public Step2VM Step2 { get; set; }
    public Step3VM Step3 { get; set; }
    public int StepIndex { get; set; }
}

Step2 View

@model WizardTest.ViewModel.WizardVM

@{
    ViewBag.Title = "Step2";
}

<h2>Step2</h2>

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)

    @Html.HiddenFor(model => model.Step1.Foo)
    @Html.HiddenFor(model => model.StepIndex)    
    <fieldset>
        <legend>Step2VM</legend>


        <div class="editor-label">
            @Html.LabelFor(model => model.Step2.Bar)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Step2.Bar)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

Controller

    public ActionResult Index()
    {
        var vm = new WizardVM
            {
                Step1 = { Foo = "test" }, 
                StepIndex = 1
            };

        return View("Step1", vm);
    }

    [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
    [HttpPost]
    public ActionResult Index(WizardVM model)
    {
        switch (model.StepIndex)
        {
            case 1:
                model.StepIndex = model.StepIndex + 1;
                return View("Step2", model);
            case 2:
                model.StepIndex = model.StepIndex + 1;
                return View("Step3", model);
            case 3:
                //Submit here
                break;
        }

        //Error on page
        return View(model);
    }

Upvotes: 1

Views: 290

Answers (2)

AaronLS
AaronLS

Reputation: 38367

Inspect the Step2 page in the browser and view the value of the hidden field to ensure it has a value of 2.

Put a break point in Index(WizardVM) to inspect to see that the value of 2 is being posted in from Step2. There are cases where the previous value will get restored from model data. Sometimes you need to call ModelState.Clear() or .Remove("ProeprtyName")

This will allow you to narrow down exactly where the problem is.

Upvotes: 1

JabberwockyDecompiler
JabberwockyDecompiler

Reputation: 3390

Thank you AaronLS for pointing me in the right direction. The changes from above that are needed are as follows.

In the View pages change HiddenFor to Hidden like so ...

@Html.Hidden("StepIndex", Model.StepIndex)

And modify the Controller to remove the Hidden field at each post like so ...

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
    [HttpPost]
    public ActionResult Index(WizardVM model)
    {
        ModelState.Remove("StepIndex");

Credit to Darin Dimitrov for the solution.

Upvotes: 1

Related Questions