MVC DropDownListFor() Selected Item is not Selected / Required Validation not run - asp.net-mvc-3

I am having trouble getting my DropDownList to set the selected item to the value from the model.
The field in the model is just a string for the Title of the users name (Mr, Miss etc..) Below is my code so far.
<td>
#{ var list = new List<SelectListItem>(new[] {
new SelectListItem{ Selected = string.IsNullOrEmpty(Model.Title), Text="",Value=""},
new SelectListItem{ Selected = Model.Title.Equals("Mr"), Text="Mr",Value="Mr"},
new SelectListItem{ Selected = Model.Title.Equals("Mrs"), Text="Mrs",Value="Mrs"},
new SelectListItem{ Selected = Model.Title.Equals("Miss"), Text="Miss",Value="Miss"},
new SelectListItem{Selected = Model.Title.Equals("Ms"), Text="Ms",Value="Ms"}
});
}
#Html.DropDownListFor(m=>m.Title, list)
</td>

I had this problem with MVC 3 and it turned out that I had set ViewBag.Title on my View (using it for the page title). As soon as I changed it to ViewBag.PageTitle, the dropdownlist code started working : #Html.DropDownListFor(model => model.Title, Model.MySelectList)
The reason for this is that in MVC 2/3, any ViewBag / ViewData properties with the same name as those in the Model object get used in preference in DropDownListFor(), so you need to rename them to make sure they don't conflict. Because that seems really flaky, I just stopped using ViewBag entirely and now rely only on the View Model for passing stuff into the View.
The reason this problem is so prevalent is that ViewBag.Title is used in many introductory tutorials and demo code to set the HTML title element, and so inevitably gets adopted as a "best-practice" approach. However, Title is a natural Model property name for use in dropdowns on a "User Details" view.

So it turns out that the only reason it doesn't work is because my field name is Title, I changed it to Prefix and my exact code works. Way too much time spent finding that out...
Here is working code.
<td>
#{ var list = new List<SelectListItem>(new[] {
new SelectListItem {
Selected = string.IsNullOrEmpty(Model.Prefix),
Text="",
Value=""
},
new SelectListItem {
Selected = Model.Prefix.Equals("Mr"),
Text="Mr",
Value="Mr"
},
new SelectListItem {
Selected = Model.Prefix.Equals("Mrs"),
Text="Mrs",
Value="Mrs"
},
new SelectListItem {
Selected = Model.Prefix.Equals("Miss"),
Text="Miss",
Value="Miss"
},
new SelectListItem {
Selected = Model.Prefix.Equals("Ms"),
Text="Ms",
Value="Ms"
}
});
}
#Html.DropDownListFor(m => m.Prefix, list)
</td>

Related

Kendo ui mvc dropdownlistfor with boolean type value using Entity Framework

#Html.Kendo().DropDownListFor(model => model.Is_Active)
//instead of #Html.EditorFor(model => model.Is_Active)"
I am using entity crud operation and Is_Active is a boolean type value. On generating edit view it shows dropdown list which code is
#Html.EditorFor(model => model.Is_Active)
and I want to change it in kendo ui using
#Html.Kendo().DropDownListFor(model => model.Is_Active)
but it shows blank dropdown list - please provide a response
You need to specify the DataSource for the DropDownList otherwise there is no list of items in it. You use the .BindTo() for that.
Html.EditorFor() works because the internal implementation for a boolean creates the True/False item list for you.
When you explicitly define a DropDownList you need to provide both the value AND the list of potential values using .BindTo(), i.e.
#{
var boolDataSource = new List<SelectListItem>()
{
new SelectListItem() { Text = "True", Value = "True" },
new SelectListItem() { Text = "False", Value = "False" }
};
// Or however/wherever you want to define the list of items that the DropDownList uses.
}
#Html.Kendo().DropDownListFor(model => model.Is_Active).BindTo(boolDataSource)

DropDownList Initial Value Duplicated - MVC 5

I have a #foreach in my View that makes a table. Each row has two items within it's td. When I click my Edit button, the visible item's in a row disappear (DislayFor's) and the hidden items in the row appear (DropDownList)
View Code
<td class="col-md-3">
<span class="item-display">
<span style="font-size: 17px">
#Html.DisplayFor(modelItem => item.Movie.Name)
</span>
</span>
<span class="item-field">
#Html.DropDownList("movieID", item.Movie.Name)
</span>
</td>
By doing this I can select a new value in the DropDownList and then Save that change to my Database (then hiding the DropDownList and unhiding the DisplayFor.
Everything works fine, however I have an issue with the initally selected value, it appears twice with the initial value having an actual value of 0 (which relates to nothing in the DB).
Picture Example
QUESTION:
Right now my dropdown add's a value upon clicking Edit, the item initially selected has the correct name but it is given the index of 0 (which is invalid for my database).
I want to have the initially selected item to NOT be added, but rather to set the selector of the dropdown to the CORRECT INDEX of the appropriate item. I am not sure why it duplicates my selected item twice.
Controller Code
public ActionResult Index(string Filter, string searchString)
{
if (String.IsNullOrEmpty(searchString) || String.IsNullOrEmpty(Filter) || (Int32.Parse(Filter) == 0))
{
ViewBag.employeeID = new SelectList(db.Employees, "ID", "Name", );
ViewBag.movieID = new SelectList(db.Movies, "ID", "Name", initiallySelectedValue);
ViewBag.roleID = new SelectList(db.Roles, "ID", "RoleType");
var movieemployees = db.MovieEmployees.Include(m => m.Employee).Include(m => m.Movie).Include(m => m.Role);
return View(movieemployees.ToList().OrderBy(x => x.Employee.Name));
}
else
{
ViewBag.employeeID = new SelectList(db.Employees, "ID", "Name");
ViewBag.movieID = new SelectList(db.Movies, "ID", "Name");
ViewBag.roleID = new SelectList(db.Roles, "ID", "RoleType");
var parameter = Int32.Parse(Filter);
return View(db.MovieEmployees.Include(m => m.Employee).Include(m => m.Movie).Include(m => m.Role).Where(x => (parameter == 1 && x.Movie.Name.Contains(searchString)) || (parameter == 2 && x.Employee.Name.Contains(searchString)) || (parameter == 3 && x.Role.RoleType.Contains(searchString))).Distinct().ToList().OrderBy(x => x.Employee.Name));
}
}
Your understanding of the parameters for DropDownList isn't quite correct, but you're close! The second parameter for DropDownList (in your case item.Movie.Name) is adding an option label. If you replaced that with a hard-coded string that would serve as a good example of what it's doing (you would see that string as the first option of every select input).
It sounds to me like you want to delete that last parameter since it will only end up serving as a duplicate. Your code would simply look like this:
#Html.DropDownList("movieID")
The important part of your code is where you're building the object that you're storing in ViewData with the key movieID. You didn't post your controller code, but I imagine it looks something like:
var movies = movieRepository.GetAllMovies();
ViewData["movieID"] = new SelectList(movies, "Name", "Id", initiallySelectedValue);
Where Name and Id are the names of properties on the movie object and initiallySelectedValue is rather self explanatory.
Edit
Here is an example of how I would go about solving your problem:
Controller
public ActionResult Index() {
//Get all the possible movies that can be selected
var movies = movieRepository.GetAllMovies();
//Get a list of employees with their related favorite movie record
var employeesWithFavoriteMovie = movieRepository.GetEmployeesWithMovie();
var employeeModels = new List<EmployeeModel>();
//Iterate through the list of employees and their favorite movie, and build the model
foreach (var employeeWithFavoriteMovie in employeesWithFavoriteMovie) {
employeeModels.Add(new EmployeeModel() {
FirstName = employeeWithFavoriteMovie.FirstName,
FavoriteMovieId = employeeWithFavoriteMovie.Movie.Id,
MovieSelectList = new SelectList(movies, "Name", "Id", employeeWithFavoriteMovie.Movie.Id)
});
}
return View(employeeModels);
}
View
#model IEnumerable<WebApplication1.Controllers.EmployeeModel>
#foreach (var employeeModel in Model) {
#Html.DropDownList("Test", employeeModel.MovieSelectList)
}
Notice how a SelectList was built for each employee and that each list is then populated with that employees current favorite movie id. This will now put you in a position to have a properly built SelectList for each employee.
#Html.DropDownListFor(model => model.classmasterd_HCF[i].TD_TEACHER, new SelectList(Model.Teacher, "ParamKey", "ParamValue", Model.classmasterd_HCF[i].TD_TEACHER) as SelectList, new { #class = "form-control input-sm DtlField EditableCtrl", #style = "min-width:100%;", #disabled = "disabled" })
where Teacher in Model.Teacher is a model with code in paramKey and description in paramvalue. Selected value saved in TD_TEACHER field

Loop through IEnumerable in #Html.DropDownListFor (MVC3)

I have a collection of models that I am passing to my view and I want to display each model.property in the dropdownlist. The problem is there is a bug in my code where it shows two duplicate items.
#model IEnumerable<UserManager.Models.vw_UserManager_Model>
#Html.Label("BRAD Module:")&nbsp
#Html.DropDownListFor(model => model.FirstOrDefault().module_name, Model.Select(x => new SelectListItem { Text = x.module_name, Value = x.module_name }), new { id = "ddlSelectedBrad", onchange = "chkSelection()" })
I am currently using FirstOrDefault() to access the module name for each model in my collection of models. But by doing this I have a duplicate value.
See screenshots below:
MARKET:LEISURE is showing twice
Intelligence is showing twice. If I change this dropdown value and return to this screen it will show two duplicate values.
Summary
Does anyone know a better way of writing the LINQ query?
Thanks.
Instead of
Model.Select(x => new SelectListItem { Text = x.module_name, Value = x.module_name })
Try
Model.GroupBy(x => x.module_name).Select(x => new SelectListItem { Text = x.First().module_name, Value = x.First().module_name })
This should filter the duplicate records.

SelectList doesn't show the selected item

This is pared down a bit, but essentially I've got a model that looks something like this:
public class PersonCreateEditViewModel
{
public string Title { get; set; }
public IEnumerable<SelectListItem> Titles { get; set; }
}
and on my edit page I want to display the person's current title in a DropDownList so we can change their title. That code looks like this:
#Html.DropDownListFor(model => model.Title, new SelectList(Model.Titles, "Value", "Text", Model.Title))
and I populate it in my action like so by retrieving a bunch of strings:
IEnumerable<SelectList> titles = somelistoftitles.Select(
c => new SelectListItem
{
Value = c,
Text = c
};
var viewModel = new PersonCreateEditViewModel()
{
Title = model.Title,
Titles = sometitles
};
return View(viewModel);
and this populates the DropDownList with the values but does not select the person's current title. So, I'm obviously doing something wrong here. Looking at the underlying html, I see that the selected attribute is not set for the option corresponding to the person's Title. I thought that specifying Model.Title there as the third argument would select it.
Ideas?
Update
I added the setting of the Selected property as qntmfred suggested below, and that'll set the right one in the list to true but the <option> doesn't have the selected attribute on it.
SOLVED
So, this was subtle. I just so happened to have a ViewBag entry named "Title" - something like this:
#{
ViewBag.Title = "Edit Person"
}
and this evidently caused the selection to not work since my model has a "Title" property as well. I solved the problem by renaming the property.
SOLVED
As I wrote at the end of my question, this wasn't an obvious thing. I just so happened to have a ViewBag entry named "Title" - something like this:
#{
ViewBag.Title = "Edit Person"
}
and this evidently caused the selection to not work since my model has a "Title" property as well. I solved the problem by renaming the property.
Way too much time wasted on this problem this morning.
Lesson learned.
You need to set the Selected property on your SelectListItem
IEnumerable<SelectList> titles = somelistoftitles.Select(
c => new SelectListItem
{
Value = c,
Text = c,
Selected = (c.Equals(model.Title))
};

ViewBag oddity in creating a MultiSelectList

I have spent a lot of time scouring the various forums for help on MultiSelectLists in asp.net MVC3. Finally figured out how to solve my issue now I'm trying to cut down on my code and I've come across something weird with ViewBags. First the code, than I'll explain the behavior.
My function that creates the MultiSelectList to used by the Controller
public MultiSelectList GetPermissionList(string[] selectedValues)
{
List<SelectListItem> permissions = new List<SelectListItem>()
{
new SelectListItem{ Value = "", Text = "None"},
new SelectListItem{ Value = "View", Text = "View"},
new SelectListItem{ Value = "Add", Text = "Add"},
new SelectListItem{ Value = "Edit", Text = "Edit"},
new SelectListItem{ Value = "Delete", Text = "Delete"}
};
return new MultiSelectList(permissions, "Value", "Text", selectedValues);
}
partial code from the edit action from the controller
public ActionResult Edit(int id)
{
ViewBag.Title = "Edit a Security Role";
SecurityRoles securityroles = Repository.Details(id);
ViewBag.Orders = securityroles.Orders.Split(',');
ViewBag.OrdersListBox = GetPermissionList(ViewBag.Orders);
return View(securityroles);
}
partial code from the View
<td class="rightAlign topAlign editor-label">
#Html.MyLabel(m => m.Orders, "lblOrders")
</td>
<td class="editor-field">
#Html.ListBoxFor(m => m.Orders, ViewBag.OrdersListBox as MultiSelectList, new { size = "5" })
</td>
Keep in mind I've cut out a large chunk of code from the edit Action, I have roughly 9 list boxes I'm creating for this security role manager.
My goal, in the edit action is to simply have 1 line of code, calling the GetPermissionList and having it return to the viewbag so I can just display that in the view, as opposed to the 2 lines per listbox that I currently have.
Just looking at the code, it seems obvious if I were to make the call this way:
ViewBag.OrdersListBox = GetPermissionList(securityroles.Orders.Split(','));
It should work, but the selected values do not come through. To compound the oddity, here is something else I tried and it worked fine, but it makes no sense why.
ViewBag.Orders = securityroles.Orders.Split(',');
ViewBag.OrdersListBox = GetPermissionList(securityroles.Orders.Split(','));
ViewBag.Orders plays no role in the ViewBag.OrdersListBox nor is it used in the view, but when I simply assign it a value than the 2nd line of code works.
Does this make sense to anyone? Any suggestions on how to create a way for the GetPermissionList to simply work correctly by sending it a string array instead of passing it the ViewBag object?
I think, You have to set Orders because that is what the selected values are being bound to when the selection happens. You could just pass a string[] if you didn't want to have anything preselected. Check out Darin's answer in this post. He is using a model but i think the same concept applies to view bag.
Multiselect with ViewModel

Resources