ASP.NET MVC - How to keep collections value when calls an Action? - asp.net-mvc

I have a ViewModel like this:
public class MyViewModel
{
public string SelectedItem { get; set; }
public List<MyClass> Items { get; set; }
}
I fill these items on screen with a #Html.DropDownListFor(m => m.SelectedItem, new SelectList(...)).
Ok, but when I call any action which receives this ViewModel, I got this collection empty.
Is there a way to get back the DropDownList values when I call any action?

That's a normal behavior and it's how HTML works. Only the selected value of a <select> element is sent to the server, not the entire collection. In your POST action if you want to retrieve the collection all you have to do is exactly the same you did in your GET action to retrieve it in the first place. That's usually a database call. And if you are afraid that you might be hitting your database quite often, just cache the collection.

In a tag form you can only send the value selected in the tag select, in this case the value of SelectedItem.
If you need also send the list of values ​​of Items, you have to create something like this:
#{
var ind = 0;
foreach(var item in Model.Items)
{
<input type="hidden" name="Items[#ind].Id" value="#item.Id"/>
ind++;
}
}
But id you can send the data by Ajax, in this case is mode simple, because you can create the data to send. See this plugin toDictionary

One way is to have the List<SelectListItem> as part of the view model and populate it via a method called from the controller and pass it to the view, e.g.
View model:
public List<SelectListItem> SelectList { get; set; }
And in the view:
#Html.DropDownListFor(model => model.SelectedItem, Model.SelectList)

Related

In a post method, how to get compact parameters instead of all the object properties

Maybe the title is not so explicitly. Let me explain you my situation
I've got a get and post method in my controller. In the GET method, gets the entities from the database context
[HttpGet]
public ActionResult RecheckAssignment(short id)
{
var assignment = db.Assignments.Find(id);
Session["QuestionList"] = QuestionRepositoryManager.GetAllPossibleQuestionsFromJson(assignment.Content); // it's a list!
return View(Session["QuestionList"]);
}
Assignment entity contains as 10 properties. When I show this entities in the model, it shows uses all the properties, but when the user does post should get only two properties from it (Id string, Changed bool) in the POST METHOD.
I do not what to put inside of the method parameters.
[HttpPost]
public ActionResult RecheckAssignment(...)
{
return View();
}
I put everything in a session variable because later I must have to get the entities again, I guess this is a good option using Session but I'm not sure.
So, what should I have to write inside of the method to get only the Id and Changed properties to updated the entities.
When ASP.NET MVC maps a <form> back to the Action during a POST it will fill in what it can. Consider a class like this:
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }
}
and now consider this form:
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post))
{
Html.TextBoxFor(m => m.Make)
}
and now consider this Action:
public ActionResult ActionName(Car model)
{
// the values of Car will look like this
model.Make // this will be what was in the text box
model.Model // this will be null
model.Year // this will be 0
}
and take note that null and 0 are the default values for those types. So, if I wanted to POST the property Model I need to get it in the form. I can do that with #Html.TextBoxFor, but what if I don't want the user to see it? Well, I can do that too:
Html.HiddenFor(m => m.Model);
and so now when the form is POSTed it will populate the Model with the value it was downloaded with. So, just make sure that all the properties you need are in the form in some way.

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))

DropDownListFor() bindling value AND text to viewmodel

I have a form on a View with a dropdown list, implemented with DropDownListFor(). This View is strongly typed to a ViewModel, which has a SelectList property to hold the options of the dropdown, and then another property to hold the selected value of the dropdown. This is working fine, but what I'd like to do is, hold both the selected value AND selected text of the dropdown in my second property. The reason I want to do this is so that as the form selfposts, I have both the text and value of each selection.
I tried changing the selected value property from an int to a KeyValuePair but only the int part of the pair is set on form submission.
Perhaps there is a better way altogether to accomplish this, I am open to all suggestions including a partial redesign of my methods.
Controller (building SelectList)
SelectList leadTypeGroups = new SelectList(_enrollmentRepository.GetLeadTypeGroups(), "Key", "Value");
ViewModel
public KeyValuePair<int, string> LeadTypeGroupID { get; set; }
public SelectList LeadTypeGroups { get; set; }
View
#Html.DropDownListFor(selected => Model.LeadTypeGroupID, Model.LeadTypeGroups, " ")
Have the sever pull the values from the database (or an in-memory cache) on each request. Alternatively, have a hidden field with javascript that updates it with the appropriate text whenever the dropdown selection changes.
Change the ViewModel to a List and then use a for loop to spit out a drop down for each item in the list. Something like...
View
#for( int i = 0; i < Model.LeadTypeGroupIDs; i++ )
{
#Html.DropDownListFor(x => Model.LeadTypeGroupIDs[i], Model.LeadTypeGroups, " ")
}
ViewModel
public List<string> LeadTypeGroupIDs { get; set; }
public SelectList LeadTypeGroups { get; set; }

Best practice for drop down boxes for web framework (ASP.NET MVC / ROR / Anything really)

I'm trying to work out a best practice for building drop down boxes for values that need to bind to values in a database.
Currently I am about to use the 3rd answer from this list How do you create a dropdownlist from an enum in ASP.NET MVC?
But then I was thinking if I bind strongly against the Enum, and then want to change the order of the items, or add new items, I'll need to make sure the order of the enum isn't actually the value being stored in the db, and have to have a binding layer of some kind.
Does anyone have the definitive way to work with drop down lists that relate to a db?
Personally I avoid using enums in my view models. They don't play well with ASP.NET MVC. So if I need to render a dropdown list in one of my views I define 2 properties on my corresponding view model:
public class MyViewModel
{
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
that are populated in my controller action from the database and in the view:
#Html.DropDownListFor(x => x.SelectedValue, Model.Values)
Have a strongly typed view model for the list with a partial view to match. Have an action in a controller which fills the view model and then returns it to the view. Wherever you want to use the dropdown, insert the partial view in your view.
I'm a fan of using an extension method for this task:
public static List<SelectListItem> ToSelectList<T>( this IEnumerable<T> enumerable, Func<T, string> value, Func<T, string> text, string defaultOption)
{
var items = enumerable.Select(f => new SelectListItem()
{
Text = text(f) ,
Value = value(f)
}).ToList();
if (!string.IsNullOrEmpty(defaultOption))
{
items.Insert(0, new SelectListItem()
{
Text = defaultOption,
Value = "-1"
});
}
return items;
}
Within your controller you select the data that you wan't to represent as items within a drop down. Note, in this example I'm selecting cities from the db:
SomeModel.City =
(from l in _locationRepository.GetAll() select new { l.Area.AreaDescription })
.Distinct()
.ToSelectList(x => x.AreaDescription, x => x.AreaDescription, "All");
And the actual drop down within the view:
#Html.DropDownList("City", Model.City)

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)

Resources