NickK
NickK

Reputation: 77

How to properly populate drop downs from ViewData in controller on multiple views in ASP.NET MVC

I've said this about a million times already, but I'm still new to ASP.Net MVC (and ASP.NET in general) so sorry if this is a bit obvious...

Ok, I have a controller which sends data to two views. One view just lists data from a database, while the other allows you to edit and add records respectively (they use the same view, with different arguments passed in).

The edit view is where my question lies. I have four drop downs in the form that are populated with data from my repository (coming from 3 different tables in my database). This all works 100% absolutely fine with the code below, no errors.

My question is what is the best way to populate these drop downs? Currently, I have my view code like so, passing data through ViewData in the controller:

Edit View:

public ViewResult EditJob(int jobId)
{
    IList<JobCust> customerList = jobsRepository.JobCustomers.OrderBy(Customer => Customer.CompanyName).ToList();
    ViewData["customers"] = new SelectList(customerList, "CompanyName", "CompanyName");

    IList<JobVehicle> vehicleRegList = jobsRepository.JobVehicles.OrderBy(Vehicle => Vehicle.VehicleReg).ToList();
    ViewData["vehicleReg"] = new SelectList(vehicleRegList, "VehicleReg", "VehicleReg");

    IList<JobVehicle> vehicleTypeList = jobsRepository.JobVehicles.OrderBy(Vehicle => Vehicle.VehicleType).ToList();
    ViewData["vehicleType"] = new SelectList(vehicleTypeList, "VehicleType", "VehicleType");

    IList<JobDriver> driverList = jobsRepository.JobDrivers.OrderBy(Driver => Driver.LastName).ToList();
    ViewData["LastName"] = new SelectList(driverList, "LastName", "LastName");

    var job = jobsRepository.Jobs.First(x => x.JobID == jobId);
    return View(job);
}

Add View:

public ViewResult AddJob()
{
    IList<JobCust> customerList = jobsRepository.JobCustomers.OrderBy(Customer => Customer.CompanyName).ToList();
    ViewData["customers"] = new SelectList(customerList, "CompanyName", "CompanyName");

    IList<JobVehicle> vehicleRegList = jobsRepository.JobVehicles.OrderBy(Vehicle => Vehicle.VehicleReg).ToList();
    ViewData["vehicleReg"] = new SelectList(vehicleRegList, "VehicleReg", "VehicleReg");

    IList<JobVehicle> vehicleTypeList = jobsRepository.JobVehicles.OrderBy(Vehicle => Vehicle.VehicleType).ToList();
    ViewData["vehicleType"] = new SelectList(vehicleTypeList, "VehicleType", "VehicleType");

    IList<JobDriver> driverList = jobsRepository.JobDrivers.OrderBy(Driver => Driver.LastName).ToList();
    ViewData["LastName"] = new SelectList(driverList, "LastName", "LastName");

    return View("EditJob", new Job());
}

I have that big block of duplicate code there that is bugging me. I know there will be a better solution, but I just don't know what it is. I now want to use this same set of drop downs on another view within this controller, so I'll be duplicating this code for a third time using my current method.

Any ideas? Maybe it's something obvious I'm totally overlooking... Thanks in advance for the help.

Upvotes: 3

Views: 514

Answers (2)

Pete
Pete

Reputation: 10871

What you're looking for is a ViewModel as described in the Nerd Dinner Tutorial. It's a custom, strongly typed representation of all the data that you need in your view including data to populate dropdowns. Swaffs answer is good and pretty complete. I just wanted to give you another reference. Good luck!

Upvotes: 0

Swaff
Swaff

Reputation: 13621

You can create a PartialView that accepts as it's model a view model that is designed to contain the data for those four drop down lists.

Then have some service method that returns that view, this may then be called from any controller and then either passed straight to your views, or added as a child object to another view model that then passes it down to your PartialView.

// a view model class to contain the SelectLists that will be rendered as drop downs
public class DropDownViewModel
{
    public SelectList Customers{get;set;}
    public SelectList VehicleReg{get;set;}
    public SelectList VehicleType{get;set;}
    public SelectList LastName{get;set;}
}

// another view model that contains a child DropDownViewModel
// object and also the Job object. This is what the Add and Edit Views
// will be responsible for rendering
public class JobsViewModel
{
    public DropDownViewModel DropDownViewModel {get;set;}
    public Job Job {get;set;}
}


// a service level class that will be responsible for constructing the 
// DropDownViewModel object and populating with the required data
public class DropDownService
{
    public DropDownViewModel GetDropDownViewModel()
    {
        // data access code
    }
}

Then in your controllers

public ViewResult AddJob()
{
    // get the view model
    DropDownService service = new DropDownService();
    DropDownViewModel dropDownViewModel = service.GetDropDownViewModel();

    // create the wrapping JobViewModel that will contain the DropDownViewModel
    JobViewModel viewModel= new JobViewModel();
    viewModel.Job = new Job();
    viewModel.DropDownViewModel = dropDownViewModel;
    return View(viewModel);
}

public ViewResult EditJob(int jobId)
{
    // get the view model
    DropDownService service = new DropDownService();
    DropDownViewModel dropDownViewModel = service.GetDropDownViewModel();

    // create the wrapping JobViewModel that will contain the DropDownViewModel
    JobViewModel viewModel= new JobViewModel();
    viewModel.Job = jobsRepository.Jobs.First(x => x.JobID == jobId);
    viewModel.DropDownViewModel = dropDownViewModel;

    return View(viewModel);
}

In your mark up, you will need to ask your Add/Edit views to pass the model data down to the PartialView which you can do like this:

<% Html.RenderPartial("MyPartialView", Model.DropDownViewModel); "%>

Upvotes: 4

Related Questions