How to Specify SelectedValue for SelectList? - c#

In my MVC Project, I have a Course model looks like this:
public class Course
{
[Key]
public int CourseId { get; set; }
[Required, MaxLength(50)]
public string Name { get; set; }
// bunch of other properties
}
I'm creating a SelectList for some Courses in my Action
var user = context.Users.Include("Courses")
.FirstOrDefault(x => x.Email == User.Identity.Name);
var courses = user.Courses.OrderBy(x => x.Name);
ViewBag.Courses = new SelectList(courses, "CourseId", "Name");`
I have a nullable courseId parameter in my Action like this:
public ActionResult Index(int? courseId)
If it's not null, I want to change the default selected value to that course.In order to do this I tried:
if (courseId != null)
{
var selectedCourse = courses
.FirstOrDefault(x => x.CourseId == courseId.Value);
if (selectedCourse != null)
{
ViewBag.Courses = new SelectList(courses, "CourseId", "Name", selectedCourse.CourseId);
}
}
But it doesn't work and selectedCourse is not null.Instead of specified Course I see the first course in my list selected every time.What am I missing ?
Edit: I'm creating DropdownList in my View like this:
#Html.Bootstrap().DropDownList("Courses", (SelectList)ViewBag.Courses)

You should send the selected value via your model, but, if you want to send it via viewbag, please try like so:
#Html.DropDownListFor(model => Model.CourseId,
new SelectList(ViewBag.Courses, "Value", "Text", #ViewBag.CourseId))
Please see my original answer to a similar question here for more info https://stackoverflow.com/a/16799915/1477388

If any answers solve your problem. Try it
put your selected value into a ViewBag.Seleted
$("#DropDownId option").each(function(){
if($(this).val() == "ViewBag.Selected"){
$(this).attr("selected","selected");
}
});

Related

C# Dropdown is returning different default values for different items

I have a get page that renders the edit page that looks like this
public ActionResult EditItemInstance(int id)
{
ItemInstance i = db.ItemInstances.Find(id);
var item = (from it in db.Items.Where(x => x.deleted == false)
select new
{
itemID = it.ID,
itemName = it.ItemID + ": " + it.Name
}).OrderBy(x => x.itemName).ToList();
ViewBag.ItemID = new SelectList(item, "itemID", "itemName", i.ItemID);
return View(i);
}
And in my view page I have a dropdown list that looks like this
#Html.DropDownList("ItemID", null, "-- Select --", htmlAttributes: new { #class = "form-control chosen-select" })
I want the default value to be the value of the current item I am editing. For most of the items this works correctly. But when I edit some items I get a default value of '-- Select -- '
Why is the default value working for some items but coming up as 'select' for others?
ViewBag and ViewData is not the best option to use. If you want to refactor this code soon - it will be hard to track changes you should make.
Use it only if there is no any other option. However I cannot think about case like that.
Imagine that your model contains property SelectedItem of type SelectListItem and Items of type SelectList
Then use DrodownListFor
#Html.DropDownListFor(m => m.SelectedItem, Model.Items)
Yea don't use ViewBag and ViewData to pass around data if you don't have to. Use ViewModel instead because it's strongly-typed and you don't have to cast it on your view, and you can declare additional properties to suit your needs.
Again, I am not sure the relationship between your ItemInstance and the list of Items coming back from the database, but from what you're trying to do, I am guessing there is a dropdown on the side of your edit page, and whatever the current item instance being edited would be selected on the dropdown?
public class EditItemInstanceViewModel
{
public IEnumerable<ItemOptionViewModel> AvailableItemOptions { get; set; }
public ItemInstanceViewModel ItemInstance { get; set; }
}
public class ItemOptionViewModel
{
public int ItemId { get; set; }
public string ItemName { get; set; }
}
public class ItemInstanceViewModel
{
public int ItemInstanceId { get; set; }
public string ItemInstanceName { get; set; }
// ... there might be more properties
}
Then in your controller, you can fill EditItemInstanceViewModel like this:
public ActionResult EditItemInstance(int id)
{
ItemInstance itemInstance = db.ItemInstances.Find(id);
if (itemInstance == null)
{
return HttpNotFound();
}
var availableItemOptions = (from it in db.Items.Where(x => x.deleted == false)
select new ItemOptionViewModel
{
ItemID = it.ID,
ItemName = it.ItemID + ": " + it.Name
})
.OrderBy(x => x.ItemName)
.ToList();
var vm = new EditItemInstanceViewModel
{
AvailableItemOptions = availableItemOptions,
ItemInstance = new ItemInstanceViewModel
{
ItemInstanceId = itemInstance.Id,
ItemInstanceName = itemInstance.Name
}
};
return View(vm);
}
Then on the view:
#model EditItemInstanceViewModel
#{
}
...
#Html.DropdownList("selected-item-id",
<!-- Enumerable items; Dropdown value field; Dropdown text field; Selected value; -->
new SelectList(Model.AvailableItemOptions, "ItemInstanceId", "ItemInstanceName", Model.ItemInstance.ItemInstanceId),
"-- Select --",
new { #class = "form-control chosen-select" })
...
Nice and clean!

DropdownListFor doesn't show the selected value

I am so confused how to make the dropdownlist to show the selected value.
Model:
public class SampleModel
{
public string State { get; set; }
}
Controller:
public ActionResult EditInformation()
{
ViewBag.State = new SelectList(db.States, "StateName", "StateName");
string userEmail = User.Identity.GetUserName();
Sample model = new SampleModel();
model.State = "Melbourne";
return View(model);
}
View :
#Html.DropdownListFor(m => m.State, ViewBag.State as IEnumerable<SelectListItem>, "-- Select State --")
The list is showing the states just fine, but it doesn't automatically select the value I assigned ("Melbourne"). I have tried using the selectlist constructor to assign the selectedValue, but after doing a lot of research, someone wrote that it is redundant to use the selectlist constructor if you are using Html.DropdownListFor() since you will be using the value assigned to the model.
EDIT:
Here is my db.State model:
public class State
{
[Key]
public int StateId { get; set; }
public string StateName { get; set; }
}
Again to clarify, I want to use StateName as the value and the text for the selectlistitem.
EDIT:
My full action method:
public ActionResult EditInformation()
{
//var states = ndb.States.Select(s => new SelectListItem { Text = s.StateName, Value = s.StateName , Selected = s.StateName == "Jawa Timur" }).ToList();
ViewBag.State = new SelectList(ndb.States, "StateName", "StateName");
ViewBag.City = new SelectList(ndb.Cities, "CityName", "CityName");
string[] countries = { "Indonesia" };
ViewBag.Country = new SelectList(countries);
string userEmail = User.Identity.GetUserName();
try
{
UserInformation userInfo = ndb.UserInformations.Single(m => m.Email == userEmail);
UserAccountViewModel model = new UserAccountViewModel();
model.Address = userInfo.Address;
model.Email = userEmail;
model.FirstName = userInfo.FirstName;
model.LastName = userInfo.LastName;
model.Phone = userInfo.Phone;
model.PostalCode = userInfo.PostalCode;
Debug.Print(userInfo.State);
model.State = userInfo.State;
model.City = userInfo.City;
model.Country = userInfo.Country;
return View(model);
}catch { }
return View();
}
public ActionResult EditInformation(int? id /*this will be passed from your route values in your view*/)
{
State myState = db.States.Find(id)
ViewBag.State = new SelectList(ndb.States, "StateId", "StateName", myState.StateId);
}//I only added this because this is what the question pertains to.
In your EditInformation View you need to have an actionlink to link to the user's id so that you pull up the right information, so:
EditInformation View:
#foreach (var item in Model)
{
#Html.ActionLink("Edit Information", "EditInformation", /*Controller Name if this view is rendered from a different controller*/, new { id = item.id })
}
try this:
public class SampleModel
{
public int Id { get; set; }
public string State { get; set; }
}
Controller:
public ActionResult EditInformation()
{
//Select default value like this (of course if your db.States have an Id):
ViewBag.State = new SelectList(db.States, "Id", "StateName", 1 /*Default Value Id or Text*/);
. . .
return View();
}
SelectList(IEnumerable, String, String, Object) - Initializes a new instance of the SelectList class by using the specified items for the list, the data value field, the data text field, and a selected value.
View:
#Html.DropdownList("State", null, "-- Select State --")
Or Like you do:
#Html.DropdownListFor(m => m.State, ViewBag.State as IEnumerable<SelectListItem>, "-- Select State --")
UPDATE:
You can get Selected text using jQuery like so:
Add #Html.HiddenFor(x => x.State)
#Html.DropdownListFor(m => m.State, ViewBag.State as IEnumerable<SelectListItem>, "-- Select State --", new { id = "stateId" })
#Html.HiddenFor(x => x.State)
JS:
$(function () {
$("form").submit(function(){
var selectedText= $("#stateId :selected").text();
$("#State").val(selTypeText);
});
});
Post:
[HttpPost]
public void UploadDocument(State model)
{
if(ModelState.IsValid)
{
string state = model.State;
}
}
OKAY, So after researching for quite some time, the problem lies in the naming convention. Apparently, you cannot use ViewBag.State for Html.DropdownListFor(m => m.State), this somehow causes the Html.DropdownListFor(m => m.State) to not reading the data properly.

SelectListItem checkboxes and autopopulate with using Contains()

I have a list of courses. If a user is assigned to a course, then I want that checkbox to be checked. How come the Contains() is not accepted?
ViewModel:
public class ViewUserViewModel
{
public List<Cours> Courses { get; set; }
public List<UserCours> UserCoursesList { get; set; }
public AspNetUser user { get; set; }
public IEnumerable<SelectListItem> CourseList { get; set; }
}
Controller:
[HttpGet]
public ActionResult ViewUser(string id)
{
ViewUserViewModel model = new ViewUserViewModel();
model.user = db.AspNetUsers.FirstOrDefault(U => U.Id == id);
//List all courses
List<Cours> allCourses = db.Courses.OrderBy(c => c.CourseName).ToList();
model.Courses = allCourses;
//List of courses the user is assigned to
//var selectedCourse1 = db.UserCourses.Where(uc => uc.UserId == id).ToList();
model.UserCoursesList = db.UserCourses.Where(uc => uc.UserId == id).ToList();
//checkbox list
model.CourseList = allCourses.ToList().Select(x => new SelectListItem()
{
//Selected = selectedCourse1.Contains(x.CourseID),
Selected = model.UserCoursesList.Contains(x.CourseID),
Text = x.CourseName,
Value = x.CourseID.ToString()
});
}
I'm thinking the Selected property will test if List has the value assigned, then it would return back true. Instead, it's a syntax error and has invalid arguments. How can I compare the CourseList to the UserCoursesList?
I think you should use LINQ Any method. You not posted you UserCours class definition, but I guess that it should have an ID, and might look like that:
public class Cours
{
public int Id { get; set; }
// Other properties
}
In this case your check for Selected property will be:
Selected = model.UserCoursesList.Any(uc => uc.CourseID == x.CourseID)
Some tips:
In this case it will be better to use some meaningful name instead of
x, for example course. It will improve readability of the code.
allCourses is already a list, you do not need to call ToList()
method again.
Updated code: thanks to Aleksandr
[HttpGet]
public ActionResult ViewUser(string id)
{
ViewUserViewModel model = new ViewUserViewModel();
//Which user
model.user = db.AspNetUsers.FirstOrDefault(User => User.Id == id);
//List all courses
model.Courses = db.Courses.OrderBy(Courses => Courses.CourseName).ToList();
//List of courses the user is assigned to
model.UserCoursesList = db.UserCourses.Where(UserCourses => UserCourses.UserId == id).ToList();
//checkbox list
model.CourseList = model.Courses.Select(Course => new SelectListItem()
{
Selected = model.UserCoursesList.Any(UserCourse => UserCourse.CourseId == Course.CourseID),
Text = Course.CourseName,
Value = Course.CourseID.ToString()
});
return View(model);
}

multiple select list c# mvc

I am trying to create a multiple select from a single select drop down menu.
my model originally had:
public int country_id { get; set; }
and my view had:
#Html.DropDownList("country_id", String.Empty)
to change it to multiple select i changed my model to:
public List<Country> country_id { get; set; }
and my view to:
#Html.ListBoxFor(model => model.country_id, ViewBag.ActionsList as MultiSelectList, new { #class = "multiselect", #style = "width: 450px;height:200px" })
the problem i am having is updating my databse using migration since the i am changing int to list, however, it keeps saying
"Cannot drop the index 'dbo.People.IX_country_id', because it does
not exist or you do not have permission."
I do have permission so I am not sure if I am missing something?
My list of countries is coming straight from the country database.
thanks for your inputs.
You need to populate a selectlist in the controller & pass it to the view, something like this:
var countries = from d in db.Countries
select new
{
Id = d.Id,
Name = d.Name
};
// I'd pass this in a model, but use ViewBag if that's what you're familiar with
ViewBag.ActionsList = new SelectList(countries , "Id", "Name");
And in the View:
#Html.DropDownListFor(model => model.country_id, ViewBag.ActionsList)
UPDATE:
You should use a ViewModel for this:
public class CountryList
{
// this may have to be a List<SelectListItems> to work with MultiSelectList - check.
public SelectList Countries{ get; set; }
public List<int> SelectedCountryIds { get; set; }
}
In the controller:
var model = new CountryList
{
SelectList = //assign the selectlist created earlier
}
return View(model);
In the View:
#Html.ListBoxFor(m => m.SelectedCountryIds, new MultiSelectList(#Model.Countries, "Id", "Name", #Model.SelectedCountryIds))

A better way than using ViewBag

I obtain a list of data through docs which has a list of every single department and function the currently logged in user has access to. I need to populate a distinct list of Departments for a DropDownList and a distinct list of Functions for a DropDownList on the View page. I am currently not even using docs to do this but a different LINQ query to acheive this. Is there a way I can use the current model I am passing?
var docs = (Long LINQ query that joins in four different tables and returns a model)
ViewBag.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
ViewBag.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
Code on View: (Strongly Typed Model)
#model IEnumerable<DB.Models.MasterList>
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")
Define a model that will be used in your view.
public class MyViewModel
{
public string SelectedDepartment { get; set; }
public string SelectedFunction { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
public IEnumerable<SelectListItem> Functions { get; set; }
// Your old model
public IEnumerable<MasterList> Master { get; set;}
}
In your controller, populate these collections and return your model to view.
[HttpGet]
public ActionResult ActionMethodName()
{
var model = new MyViewModel();
model.Departments = db.Departments.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
model.Functions = db.Functions.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
return View(model);
}
Inside your view, use strongly typed html helpers.
#model MyViewModel
#Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments)
#Html.DropDownListFor(m => m.SelectedFunction, Model.Functions)
When you post back your form to server, SelectedDepartment and SelectedFunction should have the values selected in your view.
You could create a ViewModel and put all this data in this ViewModel:
ViewModel
public class MyViewModel{
public object DepartmentList{get; set;}
public object FunctionList{get; set;}
public IEnumerable<MasterList> Master {get; set;}
}
Controller
var docs = (Long LINQ query that joins in four different tables and returns a model)
MyViewModel vm = new MyViewModel();
vm.Master = docs; // I guess docs is a list of Masterlist
vm.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
vm.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
return View(vm);
View
#model MyViewModel
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")
You can always create a ViewModel class for your view and put all the necessary view information in it.
You can use a framework like AutoMapper (https://github.com/AutoMapper/AutoMapper) to help you with the mapping between your database model and your view model (I belive it's best that the view won't know the database model at all), and beside the model information you can also add those lists (That's what I do, I have a property for the entity, and properties for those kinds of lists).
If you need this information in many of your views you can always create a BaseViewModel and polpulate that information in a BaseController.

Categories