I found this great answer to how I can do a wizard in ASP MVC.
multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)
I have just one question related to this. What would be the best practice to populate data into the view models?
Lets say in step 2 I have the need to display a list of data to the user. The list data comes from the DB. Would I then go ahead and create a constructor to the view model, or should I populate it in the controller?
This is how my code looks right now.
Model
[Serializable]
public class Step1ViewModel : IStepViewModel
{
public bool MyProperty { get; set; }
}
[Serializable]
public class Step2ViewModel : IStepViewModel
{
// This needs to be populated with data, I need to display it in a list
public List<string> MyList { get; set; }
}
[Serializable]
public class Step3ViewModel : IStepViewModel
{
public bool MyProperty { get; set; }
}
[Serializable]
public class PublishViewModel
{
public int CurrentStepIndex { get; set; }
public IList<IStepViewModel> Steps { get; set; }
public void Initialize()
{
Steps = typeof(IStepViewModel)
.Assembly
.GetTypes()
.Where(t => !t.IsAbstract && typeof(IStepViewModel).IsAssignableFrom(t))
.Select(t => (IStepViewModel)Activator.CreateInstance(t))
.ToList();
}
public class PublishViewModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var stepTypeValue = bindingContext.ValueProvider.GetValue("StepType");
var stepType = Type.GetType((string)stepTypeValue.ConvertTo(typeof(string)), true);
var step = Activator.CreateInstance(stepType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => step, stepType);
return step;
}
}
public interface IStepViewModel
{
}
Controller
public ActionResult Publish(int? id)
{
var publish = new PublishViewModel();
publish.Initialize();
return View(publish);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Publish([Deserialize] PublishViewModel publish, IStepViewModel step)
{
publish.Steps[publish.CurrentStepIndex] = step;
if (ModelState.IsValid)
{
if (!string.IsNullOrEmpty(Request["next"]))
{
publish.CurrentStepIndex++;
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
publish.CurrentStepIndex--;
}
else
{
// TODO: we have finished: all the step partial
// view models have passed validation => map them
// back to the domain model and do some processing with
// the results
return Content("thanks for filling this form", "text/plain");
}
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
// Even if validation failed we allow the user to
// navigate to previous steps
publish.CurrentStepIndex--;
}
return View(publish);
}
So my question is, where would I populate my list for Step2? My first thought would be to have a constructor in the Step2 view model. Second thought would be to have some logic in the controller find out which step im at, and populate it from there. But it all sounds a bit bad.