Populate dropdown from database and saving to database - asp.net-mvc

I have two tables, Location and Job
When I want to create a new job, I can select the location from a drop down list which is populated from the location table.
My create view:
public ActionResult Create(CreateJobViewModel model)
{
model.Locations = repository.GetAllLocations()
.Select(x => new SelectListItem { Text = x.State, Value = x.LocationId.ToString() })
.ToList();
return View(model);
}
and my view model:
public class CreateJobViewModel
{
public Job Job { get; set; }
public IList<SelectListItem> Locations { get; set; }
public int SelectLocationId { get; set; }
}
This all works fine, but how do i get the selected value from the drop down box and then save that value in the foreign key field of the Job table?
My post action looks like this:
[HttpPost]
[Authorize(Roles = "Employer")]
[ValidateAntiForgeryToken]
public ActionResult Create(Job job)
{
repository.AddJob(job);
return RedirectToAction("Create");
}
The post action uses Job entity and the get action uses CreateJobViewModel, during my previous projects, I only either do create or I display, I never come into a situation like this.
I am thinking something of passing the model between views???
and in my create view, I don't know which model i should use, the view model "CreateJobViewModel" or "Job" entity?
#model foo.CreateJobViewModel
or
#model foo.Job
How can I link the two models???

Here is some code of mine, similar to your problem, you can modify it by your requirements. Hope it helps.
Controller:
public ActionResult Create()
{
string selected = (from cat in dc.Category
join sub in dc.SubCategory on cat.Id equals sub.SubCategoryId
select cat.Name).First();
ViewBag.Category = new SelectList(dc.Category, "Id", "Name", selected);
var model = new SubCategory();
return View(model);
}
View:
<div> Category:</div>
<div>
#Html.DropDownListFor(model => model.CategoryId, (IEnumerable<SelectListItem>)ViewBag.Category,
new { #class = "form-control" })
</div>

You should use view model in the create and then use custom mapping logic to make Job entity and send to your business or data layer.
You can use Auto mapper for mapping between the entities.

You are thinking about this wrong. Why do you have a Job view model and a Job business object?
Your view should only know about the view model, your controller should (how you have this setup) knows about both the view model and business model, and the repository only knows about the business model.
Have the Post action return a Job View Model. Then convert the View Model to a model in the controller and pass to the repository.
There are several ways you could do this, doing this by hand in the controller, doing this in the constructor of the business object, or utilizing an automapper.
My preference is to create a new constructor for the business object that accepts a view model and copy the properties over that I need (and I do it from model to view model as well).

Related

Queries realted to Dropdown list in MVC

I am a new to ASP.NET MVC, I am developing an application. I want to bind the data in the drop down list in create view.
How to bind the data in the drop down? I have go through many question and answers here...
I have seen usually everyone suggested to use List<SelectListItem> what is its purpose?
Do I need to use ViewModel while binding the data to drop down list?
Can I get simple example where data get bind in the dropdown using viewbag?
I have created a list in controller
List<string> items = new List<string>();
and I want to pass this list to view using viewbag and simply want to bind to drop down list.
How to do this ?
I'd suggest using a ViewModel as it makes interaction with user input so much easier. Here's an example of how you might bind data from your ViewModel to a drop down in your View. First, the ViewModel:
public class CrowdViewModel
{
public string SelectedPerson { get; set;}
public IEnumerable<SelectListItem> People { get; set; }
}
So yes, you're right - use a collection of SelectListItems. I'm guessing in your case, the SelectListItem's Value and Text property will be the same. You could turn your List into IEnumerable like this:
[HttpGet]
public ActionResult Home()
{
// get your list of strings somehow
// ...
var viewModel = new CrowdViewModel
{
People = items.Select(x => new SelectListItem { Text = x, Value = x })
}
return View(viewModel);
}
Now you need to bind that ViewModel's property to the DropDown on your view. If you're using the Razor ViewEngine, the code will look something like this:
#model MyApp.ViewModels.CrowdViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.SelectedPerson, Model.People)
}
Now when you post that form, MVC will bind the selected value to the ViewModel's SelectedPerson property!
[HttpPost]
public ActionResult Home(CrowdViewModel viewModel)
{
// viewModel.SelectedPerson == whatever the user selected
// ...
}
Easy as that!
Update:
If you really want to use the ViewBag (don't do it), you can pass your list through from your Controller action like so:
[HttpGet]
public ActionResult Home()
{
ViewBag.People = new List<string> { "Bob", "Harry", "John" };
return View();
}
And then create a SelectList on your View:
#Html.DropDownList("SelectedPerson", new SelectList(ViewBag.People, Model))

MVC where should the logic go the Controller or the View Model

I have an MVC app where I'm wanting to display a dropdownlist with info from the database.
The dropdown will display info from database Cars using the table Make which is the make of the car.
So in my view I will have something like:
#model VectorCheck.ViewModels.CarsViewModel
...
#Html.DropDownListFor(modelItem => Model.MakeId, Model.Makes)
...
So somehow I need to get the view model the list of makes.
So I might have some logic to go with this say only cars that are colour Red.
var redCars = _unitOfWork.Cars(x => x.Colour == "Red");
So my question is where is the best practise to put the logic for this query. Should it go in the viewModel or controller.
The way I see it I have two Options.
Option 1: The controller.
public ActionResult Edit(int id)
{
var car = _unitOfWork.CarRepository.Get(id);
var carMakes = _unitOfWork.CarMakeRepository.Where(x => x.Colour == "Red").Select(u => new SelectListItem { Value = u.CarMakeId.ToString(), Text = u.Name });
return View("Edit", new InsertUpdateCarViewModel(car, carMakes));
}
ViewModel
public Car Car { get; set; }
public IEnumerable<SelectListItem> CarMakes { get; set; }
InsertUpdateCarViewModel(Car car, IEnumerable<SelectListItem> carMakes)
{
Car= car;
CarMakes = carMakes;
}
So in this example I get the carMakes in the controller and give them to the viewModel which is simply a container.
Opon 2: The viewModel
public ActionResult Edit(int id)
{
var car = _unitOfWork.CarRepository.Get(id);
return View("Edit", new InsertUpdateCarViewModel(car));
}
ViewModel
public Car Car { get; set; }
public IEnumerable<SelectListItem> CarMakes { get; set; }
InsertUpdateCarViewModel(Car car)
{
Car= car;
CarMakes = _unitOfWork.CarMakeRepository.Where(x => x.Colour == "Red").Select(u => new SelectListItem { Value = u.CarMakeId.ToString(), Text = u.Name });
}
So in this option I'm putting the logic to get the correct carmakes in the view model. It is more than a container.
So what I'm wanting to know is which of these ways is the correct way of doing this?
In the controller. The ViewModel should not be aware of the unit of work you are using. Also, the view model in this case would be a lot more reusable if it didn't have to rely on the logic x => x.Colour == "Red". Even though this could be moved to the arguments, in general, I believe your models (and therefor views) would be much more reusable taking care of that in the controller.
As already answered, it is the controller. To make it more memorable for you, I would put it this way. Do not let your view talk to the database directly. View asks/talks to Controller ONLY. Then obviously it makes sense for the view to send a request to the controller which forwards it to the database. Hope this helps for future!
You should add your logic to the Controller. In MVC, the ViewModel is an object that contains properties used in your view, no business logic in there.
Any answer would be very subjective but I'd suggest that having the _unitOfWork reference (or any dependancy which needs injecting) within your view model rather violent separation of concerns.
Keep it in the controller - far cleaner.

What's the proper way to get values for a dropdown from a table?

Lets say I have a a table called... Person, I guess, and it has the columns Name, Email, AgeGroupId.
AgeGroupId is an int, which relates to the table AgeGroup.
Agegroup only has two columns: Id, and AgeGroupName.
Now, In my view, which is a page to edit a 'person', I want a dropdown box that has EVERY AgeGroupName as the text, and the Id as the value.
This way, later on, I can add a new 'age group' into my age group table, and all my drop down boxes will update. Or is there a better way I should be doing this?
I'm currently passing in my model, and doing this:
#Html.DropDownListFor(model => model.AgeGroupId, #agegroups)
and at the top of the view, i'm making a SelectList with hardcoded values. I don't want them hard-coded in, I don't think? What would I do instead of #agegroup to get the list from the AgeGroups table?
Thanks.
The proper way is using ViewModels. Basically you'll have to create a viewmodel for your view and not pass the db result directly to your view. Something like:
public class PersonViewModel
{
public Person Person {get ; set;}
public Dictionary<int, string> AgeGroups { get; set; }
public PersonViewModel() {}
public PersonViewModel(int personId)
{
var ctx = new Context();
this.Person = ctx.Persons.SingleOrDefault(p => p.Id == personId);
foreach(var ageGroup in ctx.AgeGroups)
{
this.AgeGroups.Add(ageGroup.Id, ageGroup.AgeGroupName);
}
}
Then your controller method will look like this:
public ActionResult Add(PersonViewModel vm)
{
var ctx = new Context();
if(ModelState.IsValid)
{
ctx.Persons.Add(vm.Person);
return View("Index");
}
return View(vm);
}
And in your view, simply:
#Html.DropDownListFor(model => model.Person.AgeGroupId,
new SelectList(model.AgeGroups, "Id", "AgeGroupName"))
Of course, your view's model is now PersonViewModel.
Update
seems like ASP.NET MVC 3 Tools update adds drop down for relations by default. More info here.
The correct way seems to be from Kamyars edit, on the msdn blog here:
http://blogs.msdn.com/b/joecar/archive/2011/04/15/asp-net-mvc-3-tools-update.aspx

ASP.NET MVC - drop down list selection - partial views and model binding

I'm fairly new to ASP.NET MVC and am trying to work out the best way to do this. It's probably simple but I just want to do things correctly so I thought I'd ask.
Lets say I have a model that is this:
Task - Id, Description, AssignedStaffMember
StaffMember - Id, FirstName, LastName
and in my view I want to create a new task. I make a strongly typed Razor view, and can use EditorFor to create textboxes for Description but what about AssignedStaffMember?
I want a drop down list of all current staff and have the option of selecting one, then this gets submitted to an action method which is
NewTask(string description, StaffMember assignedStaffMember)
either that or I could have an int for staffId instead of the StaffMember object and look it up in the action method.
What is the best way to do this? I need to go to the database to get the list off staff, so here's what I thought:
Make a partial view for the listing of staff drop down, which will be used a few times and use #Html.Action("ListStaff", "Staff") to call it. The action method then has
public ActionResult ListStaff()
{
IEnumerable<StaffMember> model = _serviceLayer.GetAllStaff();
return PartialView(model);
}
However I'm not sure on how this will work with model binding, my understanding is that it has to have the correct name for the form to submit it, I'd need to pass the name to the partial view to put on the element I guess?
Instead of having it call a controller to get the staff, make a ViewModel that contains my Task and a IEnumerable possibleStaff collection. possibly send this information to a partial view.
a Html Helper ?
EditorFor could somehow be used?
which one (or is there more) would be best? and how would I do the model binding?
Here is one way to do this. Create a TaskDetailsViewModel
public class TaskDetailsViewModel
{
public TaskDetailsViewModel()
{
this.Task = new Task();
this.StaffMembers = new List<StaffMember>();
}
public Task Task { get; set; }
public IEnumerable<StaffMember> StaffMembers { get; set; }
}
In Controller
public ActionResult Edit(int id)
{
var task = taskRepository.GetTaskByID(id);
var taskDetailsViewModel = new TaskDetailsViewModel();
// Populate taskDetailsViewModel from task and staff
return View(taskDetailsViewModel);
}
[HttpPost]
public ActionResult Edit(TaskDetailsViewModel taskDetailsViewModel)
{
if (ModelState.IsValid)
{
taskRepository.Save(taskDetailsViewModel.Task);
}
else
{
// Show Error
}
return View(taskDetailsViewModel);
}
In View (bound strongly to TaskDetailsViewModel)
#Html.DropDownListFor(model => model.Task.AssignedStaffMember, new SelectList(Model.StaffMembers, "ID", "FirstName", Model.Task.AssignedStaffMember))
#Html.ValidationMessageFor(model => model.Task.AssignedStaffMember)

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.
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); "%>
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!

Resources