I have come across a problem. I am currently attempting to make a users page in which some of the dropdowns are variable and determined by their 'access level'. I then want to save the data from the view into a list and then handle it in the 'Post' controller method. I found this link about a possible solution (Assign selectlist to dynamically created dropdown in MVC) but I am still running into problems.
Here is my controller code I am using to set up the data that needs to generate the dropdowns:
var permData = db.LabPermissions.Where(x => x.AccessLevel == 1).ToList();
//sets up generic dropdown data used for all dropdowns
ViewBag.DropDownData = new List<SelectListItem>
{
new SelectListItem{ Value = "0",Text = "No"},
new SelectListItem{ Value = "1",Text = "Yes"},
};
ViewModel obj = new ViewModel();
obj.DataFromController = permData;
//other viewmodel data
return("MyView",obj);
I then pass the data to my view which looks like this (this is also how the stack overflow link set up the view)
#for(int i = 0; i < Model.DataFromController.Count(); i++)
{
<div class="row">
<div class="col-md-2">
<b>#Html.DisplayFor(m => m.DataFromController[i].Lab.LabName)</b>
</div>
<div class="col-md-2">
#Html.DropDownListFor(m => m.DataFromController[i].Assigner, (SelectList)ViewBag.DropDownData, "Select One")
</div>
<div class="col-md-8">
</div>
</div>
}
After I get this set up, and run the application, this is the error I receive:
Additional information: Cannot convert type 'System.Collections.Generic.List<System.Web.Mvc.SelectListItem>' to 'System.Web.Mvc.SelectList'
And the error is placed on my #Html.DropDownListFor line of code in my view.
Thank you for any help!
Try creating a new selectlist instead and put your selectlistitems in it.
#Html.DropDownListFor(m => m.DataFromController[i].Assigner,
new SelectList(ViewBag.DropDownData, "Value", "Text", "Select One")
Or, since you got a ViewModel you can add a public property that can hold your selectlistitems.
public class ViewModel
{
public IEnumerable<SelectListItem> DropDownData { get; set; }
}
Controller:
var permData = db.LabPermissions.Where(x => x.AccessLevel == 1).ToList();
var vm = new ViewModel();
var list = new List<SelectListItem>
{
new SelectListItem{ Value = "-1", Text = "Select One", Selected = true},
new SelectListItem{ Value = "0",Text = "No"},
new SelectListItem{ Value = "1",Text = "Yes"}
};
vm.DropDownData = list;
vm.DataFromController = permData;
return View(vm);
View:
#model YourNameSpace.Models.ViewModel
#for(int i = 0; i < Model.DataFromController.Count(); i++){
#Html.DropDownListFor(m => m.DataFromController[i].Assigner, Model.DropDownData)
}
I believe that you're trying to cast SelectListItem to SelectList and that is the reason why you're getting that error. I've done the same feature as a part of my project and I'm taking the values for the dropdownlist from the database.
and for displaying, here is my code(modified a bit based on your model variables
My Controller method
public ActionResult GetDropDownList()
{
List<SelectListItem> dropDownList= new List<SelectListItem>();
using (var context = new assessmentEntities())
{
//getting data from the DB
var result = context.getDataFromDB().toList();
foreach (var item in result)
{
dropDownList.Add(new SelectListItem() { Text = item.Variable1, Value = item.Variable2});
}
ViewBag.DropDownData = dropDownList;
}
return View();
}`
Here is my View
#Html.DropDownListFor(m => m.DataFromController[i].Assigner,, new SelectList(ViewBag.DropDownData, "Value", "Text")
Hope so this works for you
Related
I am creating an web page in which have a Dropdownlist. I have to retrieve data for the drop_down_list from the database. Is there any way to get data from the database to the html view my html code:
<select name="drop down"><option value="1">#test.list[i]</option></select>
I got the database value to the list variable but I don't know how to pass the data to the html view. Please help me in this issue.Thanks
You need to create Select List of Items :
Your Action with List of Items in View Bag :
public ActionResult ActionName()
{
List<SelectListItem> Items = new List<SelectListItem>();
CustReportName.Add(new SelectListItem() { Text = "List1", Value = "1", Selected = false });
CustReportName.Add(new SelectListItem() { Text = "List2", Value = "2", Selected = true });
ViewBag.ListItems = Items;
return View("ViewName");
}
For Multiple values from database table:
public ActionResult ActionName()
{
IEnumerable<SelectListItem> ItemsList = from item in YourTableObject
select new SelectListItem
{
Value = Convert.ToString(item.Id),
Text = item.ItemName
};
ViewBag.ListItems = new SelectList(ItemsList, "Value", "Text");
return View("ViewName");
}
Your DropdownList On view :
#Html.DropDownListFor(model => model.ItemId, new SelectList(ViewBag.ItemList, "Value", "Text", 0), "-Select Item-", new { #class = "form-control", #id = "ItemId" })
Cheers !!
It is just a simple two step process:
Step1 :Action method code
public ActionResult Index()
{
ViewBag.users = db.users.ToList();
}
Step2: cshtml code
#Html.DropDownListFor(model => model.someId, new SelectList(ViewBag.users, "userId", "userName"), "Select users")
Note: with this, you can bind n number of data from the database to dropdownlist
Hope it was useful
Thanks
Karthik
Wrapping my head around MVC.
I have a list of items. I need to load the screen with some of these selected by default.
Loading the items is one thing, trying to select some by default isn't working for me.
Any idea where I am going wrong?
I know there are many answers to a similar question, though I can't seem to translate the answers to my needs.
Here is the code I have, and tried - i am also trying to understand the various options in the html helpers. Please take this into consideration when posting a solution.
This is the most recent iteration of my code; i have gone through a bunch....
In my Controller:
public ActionResult Index()
{
ViewBag.Statuses = AddStatuses();
return View();
}
private MultiSelectList AddStatuses()
{
string[] defaultSelected = { "Ready", "Done", "Error" };
List<SelectListItem> listItems = new List<SelectListItem>();
List<Status> s = allTypes.GetStatuses();
s.ForEach(status =>
{
listItems.Add(new SelectListItem()
{
Text = status.Name,
Value = status.ID.ToString(),
Selected = true,// defaultSelected.Contains(status.Name)
});
});
return new MultiSelectList(listItems, "Value", "Text");
}
In an attempt to test my defaultSelected.Contains, i just commented it out to select ALL as true... still didn't work...
I have tried these in my view
#Html.DropDownList("Statuses", null, null, new { #class = "form-control", multiple = true, id="queueStatuses" })
#Html.ListBox("Name", ViewBag.Statuses as MultiSelectList, new { #class = "form-control", id = "queueStatuses" })
#Html.ListBox("Statuses", null, new { #class = "form-control", id = "queueStatuses" })
I a) don't understand what i am doing and b) can't get it to work... :)
I am looking for:
You can use the ListBoxFor helper method along with the user of a view model to pass the items for your list box.
So create a new view model to transfer data from your action method to view
public class CreateIssue
{
public List<SelectListItem> Statuses { set;get;}
public int[] SelectedStatuses { set;get;}
}
Now in your GET action, create an object of this, load the Statuses collection and send it to the view. If you want to preselect some items, set the SelectedStatuses property.
public ActionResult Index()
{
var vm = new CreateIssue();
//Hard coded for demo. You may replace with values coming from db table.
vm.Statuses = new List<SelectListItem> {
new SelectListItem { Value="1", Text="Ready"},
new SelectListItem { Value="2", Text="Done"},
new SelectListItem { Value="3", Text="Building"},
new SelectListItem { Value="4", Text="Error"},
};
//For preselecting items, set it here
vm.SelectedStates=new int[] { 2,3};
return View(vm);
}
and your in your view, which is strongly typed to the view model, use the ListBoxFor helper method.
#model CreateIssue
#using (Html.BeginForm())
{
<label>Select many statuses</label>
#Html.ListBoxFor(m => m.SelectedStatuses, Model.Statuses)
<input type="submit"/>
}
Thank you #Shyju. I am sure your answer works.
As mentioned in my comments though, I don't want to go through the hoops of having a view model in this instance. I was looking for a simple way to implement this.
Seems all i needed to do was change my MultiSelectList and pass in an array of selected 'value's.
This fixes my issue:
private MultiSelectList AddStatuses()
{
string[] defaultSelected = { "3", "5", "6" };
List<SelectListItem> allItems = new List<SelectListItem>();
List<Status> s = allTypes.GetStatuses();
s.ForEach(status =>
{
allItems.Add(new SelectListItem()
{
Text = status.Name,
Value = status.ID.ToString(),
});
});
return new MultiSelectList(allItems, "Value", "Text", defaultSelected);
}
And my ListBox is the same. Went with this one in the end:
#Html.ListBox("status", (IEnumerable<SelectListItem>)ViewBag.Statuses, new { #class = "form-control" })
I have multiple dropdownlists which are rendered with a for loop and I'm having a problem getting them to post the selected value to the controller. In my query my selectlist is made like this:
model.CreateGroupForm.Genders = new List<SelectListItem>
{
new SelectListItem() {Text = "Either", Value = "Either"},
new SelectListItem() {Text = "Male", Value = "Male"},
new SelectListItem() {Text = "Female", Value = "Female"},
};
My first problem was even getting my dropdown to display the database value, even though I confirmed it was retrieving the correct value. It wouldn't work with this:
#for (var c = 0; c < Model.ExistingGroups.Count; c++)
{
#using (Html.BeginForm("EditGroup", "Group", new { id = Model.Id.StripCollectionName(), slug = Model.Slug, innerid = Model.ExistingGroups[c].Id }, FormMethod.Post, new { id = "editcommunityteamform" + c.ToString(CultureInfo.InvariantCulture), #class = "nomarginbottom" }))
{
...
#Html.DropDownListFor(x => x.ExistingGroups[c].Gender, Model.Createform.Genders)
<button type="submit" class="btn btn-primary" title="Update name and description of this group">Update</button>
}
}
After doing some digging on Stack, I discovered that each dropdown rendered needs it's own separate list. So I changed it to:
#Html.DropDownListFor(x => x.ExistingGroups[c].Gender,
new SelectList( Model.CreateGroupForm.Genders,"Value", "Text",Model.ExistingGroups[c].Gender))
This then correctly displays the queried value, however it just posts null to the controller when I submit the form. I'm having the same issue with a checkboxfor boolean within the for loop.
My ActionResult in the controller just expects a string value and looks like this:
public ActionResult EditGroup(EditGroupInput input)
{
var command = new EditGroupCommand(input.Gender);
....
My view model looks like this:
public IList<CommunityGroup> ExistingGroups { get; set; }
public CreateGroupInput CreateGroupForm { get; set; }
And then the above 2 classes have the properties mentioned in the code.
I've discovered the problem, which is that dropdownlistfor, checkboxlistfor etc do not like operating within a 'for' loop. I certainly don't have the technical know-how to understand why, but when I changed dropdownlistfor to dropdownlist it worked. So the solution looks like this:
#for (var c = 0; c < Model.ExistingGroups.Count; c++)
{
#using (Html.BeginForm("EditGroup", "Group", new { id = Model.Id.StripCollectionName(), slug = Model.Slug, innerid = Model.ExistingGroups[c].Id }, FormMethod.Post, new { id = "editcommunityteamform" + c.ToString(CultureInfo.InvariantCulture), #class = "nomarginbottom" }))
{
...
#Html.DropDownList("Gender", new SelectList(Model.CreateGroupForm.Genders, "Value", "Text", Model.ExistingGroups[c].Gender))
...
}
}
EditGroupInput should be a collection of ExistingGroups as controller action method are strongly binded with view.or use formcollection as parameter and see what are all the keys being posted from view to controller.
I have a dropdown in View
#Html.DropDownList("GenderAllowed", (SelectList)ViewBag.LocGenederAllowedList, new { #class = "form-control" })
and I am sending list of dropdown through ViewBag, and through model I am sending value that need to be selected in the dropdown.
But the value in dropdown is not selected.
My Controller
[HttpGet]
public ActionResult EditVendorLocation(int VendorLocationID)
{
VendorLocationHandler obj = new VendorLocationHandler();
LocationGrid objLoc = new LocationGrid();
FillGenederAllowed(objLoc);
objLoc = obj.GetVendorLocationForAdmin(VendorLocationID);
return View(objLoc);
}
Function for Viewbag
public void FillGenederAllowed(LocationGrid V)
{
Dictionary<int, string> LocGenederAllowed = EnumHelper.GetGenderStates();
SelectList LocGenederAllowedList = new SelectList(LocGenederAllowed, "key", "value");
ViewBag.LocGenederAllowedList = LocGenederAllowedList;
}
The SelectListItemsyou are passing to the DropDownList have a property Selected. In your ViewModel, set this to true for the item that should be selected initially.
You need this in your controller
ViewBag.LocGenederAllowedList =
new SelectList(db.SomeValues, "Value", "Text",selectedValue);
And in your view
#Html.DropDownList("GenderAllowed",
(SelectList)ViewBag.LocGenederAllowedList, new { #class = "form-control" })
Take a look at this class.
All you need to do is create instances of them and set the Selected property to true for the item you want to be initially selected:
public ActionResult YourActionMethod(...)
{
var selectItems = Repository.SomeDomainModelObjectCollection
.Select(x => new SelectListItem {
Text = x.SomeProperty,
Value = x.SomeOtherProperty,
Selected = ShoudBeSelected(x)
});
ViewBag.SelectListItems = selectItems;
// more code
var model = ...; // create your model
return View(model);
}
You will need this overload of Html.DropDownListFor(...) in order to use this.
You can do it in your controller action like following. Hope it helps.
ViewBag.LocGenederAllowedList = new SelectList(items, "Id", "Name", selectedValue);
dot net fiddle link: https://dotnetfiddle.net/PFlqei
I'm having the same issue as this here I believe, but the workaround is not working for me.
My issue is that I have a child collection of models inside my main view's ViewModel. They contain data to be displayed in two fields, a dropdownlist and a password field. Each dropdownlist selection must be unique. Everything is saving and being sent to the view properly, however the dropdownlist are not binding to the selected values when the view is called but the password field is. They all default to the first selection, even though the property they are suppose to bind to is unique and only one can be the first value. Any help or insight is appreciated. Thanks.
Here is the part in my view where the issue is occurring. I have commented out my efforts and tried the above link's workaround to no avail:
#functions {
private IEnumerable<SelectListItem> Mark(IEnumerable<SelectListItem> items, object Id)
{
foreach (var item in items)
if (string.CompareOrdinal(item.Value, Convert.ToString(Id)) == 0)
item.Selected = true;
return items;
}
}
#for (int j = 0; j < Model.PasswordResetQuestionUserAnswers.Count(); j++)
{
#Html.Hidden("PasswordResetQuestionUserAnswers.Index", j)
#Html.HiddenFor(p => Model.PasswordResetQuestionUserAnswers[j].Id)
#Html.HiddenFor(p => Model.PasswordResetQuestionUserAnswers[j].UserId)
<div class="form-group">
<label class="col-md-2 control-label">Password Reset Question #(j+1)</label>
<div class="col-md-6">
#*#Html.DropDownList("PasswordResetQuestionUserAnswers[" + j + "].PasswordResetQuestionId", Model.PasswordResetQuestionList, new { #class = "form-control passwordQuestion" })*#
#*#Html.DropDownListFor(x => Model.PasswordResetQuestionUserAnswers[j].PasswordResetQuestionId, Model.PasswordResetQuestionList, new { #class = "form-control passwordQuestion" })*#
#Html.DropDownListFor(x => Model.PasswordResetQuestionUserAnswers[j].PasswordResetQuestionId, Mark(Model.PasswordResetQuestionList, Model.PasswordResetQuestionUserAnswers[j].PasswordResetQuestionId))
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Password Reset Answer #(j+1)</label>
<div class="col-md-6">
#Html.Password("PasswordResetQuestionUserAnswers[" + j + "].Answer", Model.PasswordResetQuestionUserAnswers[j].Answer, new { #class = "form-control passwordQuestionUserAnswer" })
#*#Html.PasswordFor(x => Model.PasswordResetQuestionUserAnswers[j].Answer, new { #class = "form-control passwordQuestionUserAnswer" })*#
</div>
</div>
}
I just had this same problem. This syntax works for me:
#Html.DropDownListFor(x => x.ChildCollection[i].ChildID, new SelectList(ViewBag.ChildCollectionSelect as SelectList, "Value", "Text", Model.ChildCollection[i].ChildID))
Define the SelectList as new, then specifically set the selected value from the model.
This is an adaption to the example of above, for what worked for me in a similar scenario, where itm represents the child object in the collection. I'm not exactly sure what all is going on in that example -- too many "Questions", "Users", and "Answers", but say if you wanted a dropdown of users and it to be filled with the particular one that had been assigned to that child item:
foreach (var itm in Model.PasswordResetQuestionUserAnswers)
{
#Html.DropDownListFor(modelItem => itm.UserId,
new SelectList( (IEnumerable<SelectListItem>)ViewData["users"], "Value", "Text", itm.UserId),
htmlAttributes: new { #class = "form-control" }
)
}
Where you'd fill ViewData["users"] like this in the Controller method that renders the view:
var usersList = GetUsersList();
ViewData["users"] = usersList;
and have these supporting functions:
private static SelectListItem[] _UsersList;
/// <summary>
/// Returns a static category list that is cached
/// </summary>
/// <returns></returns>
public SelectListItem[] GetUsersList()
{
if (_UsersList == null)
{
var users = repository.GetAllUsers().Select(a => new SelectListItem()
{
Text = a.USER_NAME,
Value = a.USER_ID.ToString()
}).ToList();
users.Insert(0, new SelectListItem() { Value = "0", Text = "-- Please select your user --" });
_UsersList = users.ToArray();
}
// Have to create new instances via projection
// to avoid ModelBinding updates to affect this
// globally
return _UsersList
.Select(d => new SelectListItem()
{
Value = d.Value,
Text = d.Text
})
.ToArray();
}
Repository.cs
My Repository function GetAllUsers() for the function, above:
Model1 db = new Model1(); // Entity Framework context
// Users
public IList<USERS> GetAllUsers()
{
return db.USERS.OrderBy(e => e.USER_ID).ToList();
}
Users.cs
public partial class USERS
{
[Key]
public int USER_ID { get; set; }
[Required]
[StringLength(30)]
public string USER_NAME { get; set; }
}
Edit
After re-reading the question, it seems it was about posting password reset questions.
foreach (var itm in Model.PasswordResetQuestionUserAnswers)
{
#Html.DropDownListFor(modelItem => itm.PasswordResetQuestionId,
new SelectList( (IEnumerable<SelectListItem>)ViewData["pwordResetQuestions"], "Value", "Text", itm.PasswordResetQuestionId),
htmlAttributes: new { #class = "form-control" }
)
}
And you'd have to have a ViewData["pwordResetQuestions"] filled like this in the controller method that renders that view:
var questionsList = GetQuestionsList();
ViewData["questions"] = questionsList;
and these supporting functions/objects:
private SelectListItem[] _QuestionsList;
public SelectListItem[] GetQuestionsList()
{
if (_QuestionsList == null)
{
var questions = PasswordResetQuestionUserAnswers.Select(a => new SelectListItem()
{
Text = a.Answer, //? I didn't see a "PasswordResetQuestionText" call in your example, so...
Value = a.PasswordResetQuestionId.ToString()
}).ToList();
questions.Insert(1, new SelectListItem() { Value = "1", Text = "Mother's Maiden Name" });
questions.Insert(2, new SelectListItem() { Value = "2", Text = "Elementary school attended" });
_QuestionsList = questions.ToArray();
}
// Have to create new instances via projection
// to avoid ModelBinding updates to affect this
// globally
return _QuestionsList
.Select(d => new SelectListItem()
{
Value = d.Value,
Text = d.Text
})
.ToArray();
}
I hard-coded some questions in there - I kinda doubt you'd have a table for them, usually companies only have less than 10. But you could always do that database call like I did for the Users table if they were using a database table - which is why I left that example there.
I was having the same issue and fighting with it. The examples above got me over the hump, but I was able to simplify using the code the way you have it, with one modification:
Original Code
#Html.DropDownListFor(x => Model.PasswordResetQuestionUserAnswers[j].PasswordResetQuestionId, Model.PasswordResetQuestionList, new { #class = "form-control passwordQuestion" })
Update Code: (Wrap it with a new SelectList)
#Html.DropDownListFor(x => Model.PasswordResetQuestionUserAnswers[j].PasswordResetQuestionId, new SelectList(Model.PasswordResetQuestionList, "Value", "Text", Model.PasswordResetQuestionUserAnswers[j].PasswordResetQuestionId, new { #class = "form-control passwordQuestion" })
This eliminates the need for the ViewBag or ViewData.