SelectList does not select items when generated inside View - asp.net-mvc

I am having problems to preselect the items when creating SelectList inside View. Here is the Razor code:
#{
ViewBag.Title = "RoleGroupMappings";
}
<h2>Map roles to groups:</h2>
<table>
#foreach (var role in Model.Roles)
{
<tr>
<td>
<p>#role.RoleName: </p>
</td>
<td>
#using (Html.BeginForm("MapGroupsToRole", "Role", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.Hidden("RoleId", role.RoleId)
#Html.DropDownList("Groups", new SelectList(role.Groups, "GroupId", "GroupName", role.Groups.Where(g => g.Mapped).Select(g => g.GroupId)), new { #class = "directory-groups", multiple = "multiple", style = "display: none;" })
<input type="button" value="Clear All" class="btn btn-danger clear-selection" />
<input type="submit" value="Save Changes" class="btn btn-success save-mappings" />
}
</td>
</tr>
}
</table>
Does anybody know what is the problem here?

I think you want to be using a MultiSelectList instead of the normal SelectList. Try this:
#Html.DropDownList("Groups", new MultiSelectList(role.Groups, "GroupId", "GroupName", role.Groups.Where(g => g.Mapped).Select(g => g.GroupId)), new { #class = "directory-groups", multiple = "multiple", style = "display: none;" })
Update
Being as this is working for me here, I'll show you how I've setup this test project. Hopefully that will help you to narrow down what the problem is. Test model setup:
public class Role
{
public int RoleId { get; set; }
public string RoleName { get; set; }
public List<Group> Groups { get; set; }
}
public class Group
{
public Guid GroupId { get; set; }
public string GroupName { get; set; }
public bool Mapped { get; set; }
}
The view model:
public class TestViewModel
{
public List<Role> Roles { get; set; }
}
public ActionResult Index()
{
var model = new TestViewModel
{
Roles = new List<Role>
{
new Role
{
RoleId = 1,
RoleName = "Test",
Groups = new List<Group>
{
new Group
{
GroupId = new Guid("12345678-1234-1234-1234-123412341234"),
GroupName = "Group 1",
Mapped = false
},
new Group
{
GroupId = new Guid("12345678-5678-6789-1234-123412341234"),
GroupName = "Group 2",
Mapped = true
},
new Group
{
GroupId = new Guid("12345678-0000-6789-1234-123412341234"),
GroupName = "Group 3",
Mapped = true
}
}
}
}
};
return View(model);
}
My view is the same as yours, except with using MultiSelect and I also removed #class = "directory-groups" and the display: none; style. Both group 2 and group 3 have their Mapped property set to true. This is the result from loading the view:

I found a problem in my controller. I was setting the ViewBag.Groups to some values, and obviously it was interfering with my DropDownList which had the same name. Sorry for that, I was staring whole day and I could not find the error, so I become little desperate. I should have looked at my controller, too.

Related

Dropdown list population from ViewModel

First of all, I know this question has been asked many, many times. I've read countless articles and Stack Overflow answers. I've tried to figure this problem out for four days and I think I need help if someone doesn't mind.
I have two databases. The employee database has a field called "DisplayName" -- the second database has a relationship with the first and they work together great. I'm able to call the two databases perfectly in another application.
You can see the in the picture Index Page
that I have a list of people. I want a dropdown below it that lists all display names in the database so employees can add themselves to the list. You'll see a dropdown in the image but it's not populated.
Seems simple. But geez. Part of a problem I'm having is my home controller already has a function to populate the list in the picture so I can't do another on that page. I've tried a lot of suggestions on a lot of sites. I get IEnumerable errors or display reference errors....
Here's my controller (again - it has nothing in it that helps the dropdown):
namespace SeatingChart.Controllers
{
public class HomeController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Employee
public ActionResult Index()
{
var lists = db.BreakModels
.Include("Employee")
.Include("TimeEntered")
.Include("TimeCleared")
.Include("DisplayName")
.Select(a => new HomeIndexViewModels
{
Employee = a.Employee,
DisplayName = a.EmployeeModels.DisplayName,
TimeEntered = a.TimeEntered,
TimeCleared = a.TimeCleared.Value,
Id = a.EmployeeModels.Id,
});
return View(lists);
}
View:
#model IEnumerable<SeatingChart.Models.HomeIndexViewModels>
#{
Layout = null;
}
#Html.Partial("_Header")
<div class="container_lists">
<div class="container_break col-md-8">
<h5 style="text-align:center">Break List</h5>
<table class="table-bordered col-lg-12">
#if (Model != null)
{
foreach (var item in Model)
{
if (item.TimeCleared == null)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.DisplayName)
</td>
<td>
 BV
</td>
<td>
 #item.TimeEntered.ToString("HH:mm")
</td>
</tr>
}
}
}
</table>
#using (Html.BeginForm())
{
<div class="row site-spaced">
<div class="col-3">
#Html.DropDownList("DisplayName", new SelectList(new List<string>() { "---Dispatcher---" }), new { #class = "required " })
</div>
</div>
<div class="col-3">
<input type="submit" value="Submit" class="site-control" />
</div>
}
</div>
</div>
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace SeatingChart.Models
{
public class HomeIndexViewModels
{
//Break Model
public int BreakId { get; set; }
public int Employee { get; set; }
public DateTime TimeEntered { get; set; }
public DateTime? TimeCleared { get; set; }
//Employee Model
public int Id { get; set; }
public string DisplayName { get; set; }
public string DisplayNames { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool NotActive { get; set; }
public int Force { get; set; }
public string EmployeeList { get; set; }
}
}
I hope this is clear enough. I've tried so many different ways with so much code - the errors are different with everything I've tried.
Thanks in advance for your patience and help!
You can add to your viewmodel
public List<SelectListItem> Employees { get; set; }
Then you can populate this list with controller then in view just call it with:
#Html.DropDownListFor(m => m.Id, Model.Employees, new { #class = "form-control", required = "required" })
Update - how to populate list. Should work (but not tested code).
public List<SelectListItem> GetEmployeeForDropdown(List<HomeIndexViewModels> list)
{
List<SelectListItem> empList = new List<SelectListItem>();
try
{
if (list != null && list.Count > 0)
{
foreach (var item in list)
{
empList.Add(new SelectListItem { Text = item.DisplayName, Value = item.Id.ToString() });
}
}
else
{
empList.Add(new SelectListItem { Text = "No items", Value = string.Empty });
}
}
catch (Exception ex)
{
//handle exceptions here
}
return empList;
}
Edit: Remember to use your model in view!

How can I return the selected items in View?

I created a web page using asp.net MVC with Entity Framework. I want to return in the View the selected items. If I select multiple data, just the last item return. When I debug, the array receive the selected items, but in the foreach loop, just the last query return. How can I fix this?
View
#using (Html.BeginForm())
{
#Html.DropDownList("prof_id", null, htmlAttributes: new { #class = "form-control", #multiple = "multiple" })<br /><br />
<input type="submit" value="Search" />
}
Controller
public ActionResult Index(int[] prof_id)
{
ViewBag.prof_id = new MultiSelectList(db.prof, "prof_id", "name");
List<user> test = new List<user>();
foreach (var item in prof_id)
{
test = db.user.Where(u => u.prof_id == item).ToList();
}
return View(test.ToList());
}
Model
public partial class prof
{
public prof()
{
this.user = new HashSet<user>();
}
public int prof_id { get; set; }
public string name { get; set; }
public virtual ICollection<user> user { get; set; }
}
Change foreach loop inside with this,
var tempList = db.user.Where(u => u.prof_id == item).ToList();
test.AddRange(tempList);
Hope helps,

Issue on retrieving value from DropDownListFor

I have a situation where I would like administrators to re-order questions to however they like, however, I have an issue on retrieving the value selected from the "DropDownListFor" from my form to my controller.
Placing the breakpoint at "Debug.WriteLine(MV.Count), the variable "SetNewValue" returns null in my controller
So what is the proper way to retrieve the new value that is selected and my default selected value from my DropDownListFor, as well as the current question number to my controller upon "onchange = this.form.submit()"?
I know the [HttpPost] Controller part is not a proper method to swap the questions, it is there for me to see whether the variables I have set do return the values that are sent from the DropDownListFor upon "onchange" form submit.
Any form of help is appreciated, as I am a beginner in MVC.
My View
#model IList<AppXamApplication.Models.EditQuestionsAndAnswersViewModel>
#{
ViewBag.Title = "EditQuestionsPage2";
}
<h4>Edit Your Questions Here</h4>
#using (Html.BeginForm("EditQuestionsPage2", "ExamAdmin", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<table id="tblQuestions" border="0" style="border:none">
#for (int i = 0; i < Model.Count; i++)
{
if (Model[i].TypeOfQuestion == "Open Ended")
{
<tr>
<td>
#Html.DropDownListFor(m => m[i].SetNewValue, new SelectList(Model[i].TotalNoQuestions, "Value", "Text", Model[i].ToSetPreSelectValue), new { #Name = "CurrentQnAction", onchange = "this.form.submit();" })
#Html.HiddenFor(m => m[i].CurrentQuestionNumber, new { CurrentQnNoID = Model[i].CurrentQuestionNumber })
</td>
<td> </td>
<td> </td>
<td>
#Html.ActionLink("Delete Question", "EditQuestionsPage2", new { Question_ID = Model[i].QuestionID, #class = "form-control" })
</td>
</tr>
<tr>
<td>
<b>Question Type: #Html.DisplayFor(m => m[i].TypeOfQuestion, new { #class = "form-control" }) </b>
</td>
</tr>
<tr>
<td>
#Html.EditorFor(m => m[i].QuestionsAsked, new { #class = "form-control" })
</td>
</tr>
<tr>
<td>
<br />
<br />
</td>
</tr>
}
}
</table>
}
Edited: My Model
public class EditQuestionsAndAnswersViewModel
{
//Questions
public string QuestionID { get; set; }
public string TypeOfQuestion { get; set; }
public string ExamID { get; set; }
public string QuestionsAsked { get; set; }
public string UserID { get; set; }
public int? OrderingQuestions { get; set; }
public int? CurrentQuestionNumber { get; set; }
public string SetNewValue { get; set; }
public int? ToSetPreSelectValue{ get; set; }
public IList<SelectListItem> TotalNoQuestions { get; set; }
public IList<EditAnswers> PossibleAnswers { get; set; }
public string AnswerID { get; set; }
public string AnswerText { get; set; }
}
Edited: My Controllers
[HttpGet]
public ActionResult EditQuestionsPage2()
{
if (ModelState.IsValid)
{
using (var ctx = new AppXamApplicationEntities())
{
var CurrentExamID2 = (string)Session["CurrentExamID2"];
string CurrentExamID2_string = Convert.ToString(CurrentExamID2);
var query = ctx.Questions.Where(x => x.ExamID.Equals(CurrentExamID2_string))
.Select(x => new EditQuestionsAndAnswersViewModel()
{
QuestionID = x.QuestionID,
TypeOfQuestion = x.TypeOfQuestion,
ExamID = x.ExamID,
QuestionsAsked = x.QuestionsAsked,
UserID = x.UserID,
ToSetPreSelectValue= x.QuestionOrder,
// To Order the questions in ascending order
OrderingQuestions = x.QuestionOrder,
// To Display Current Question Number
CurrentQuestionNumber = x.QuestionOrder,
// To Display the dropdownlist as well as set the default selected value to be displayed for each question in the dropdownlist
TotalNoQuestions = ctx.Questions.Where (v=> v.ExamID.Equals(x.ExamID)).Select(v => new SelectListItem
{
Value = v.QuestionOrder.ToString(),
Text = v.QuestionOrder.ToString(),
}).ToList(),
PossibleAnswers = x.Answers.Where(y => y.QuestionID.Equals(x.QuestionID)).Select(y => new EditAnswers()
{
AnswerID = y.AnswerID,
AnswerText = y.AnswerText
}).ToList()
}).ToList().AsQueryable();
var queryOrdered = query.OrderBy(x=> x.CurrentQuestionNumber).ToList();
return View(queryOrdered);
}
}
return View();
}
[HttpPost]
public ActionResult EditQuestionsPage2(string action, string CurrentQnAction, int? CurrentQnNoID, IList<EditQuestionsAndAnswersCollectionModel> MV, string ToRetrieveSelectedValue, AddQuestions _model)
{
if (ModelState.IsValid)
{
if (CurrentQnNo!= null)
{
//Breakpoint placed over here
Debug.WriteLine(MV.Count);
}
}
return View();
}

allow to select only one radiobutton

I have a survey with 6 questions. Each question will be rated between (1-5). I want to capture the value selected for each question. Only one value can be selected on each question
The following is allowing me to select more than one option for each question, I should restrict to select only one for each question. All the radio buttons should be grouped as one, and only one button can be selected. I should be able to capture the selected value for each when submitted.
public class SurveyViewModel
{
public GroupViewModel GroupA { get; set; }
public GroupViewModel GroupB { get; set; }
public GroupViewModel GroupC { get; set; }
public SurveyViewModel()
{
GroupA = new GroupViewModel();
GroupA.GroupName = "A";
GroupB = new GroupViewModel();
GroupB.GroupName = "B";
GroupC = new GroupViewModel();
GroupC.GroupName = "C";
}
}
public class GroupViewModel
{
public string GroupName { get; set; }
public bool radio1 { get; set; }
public bool radio2 { get; set; }
public bool radio3 { get; set; }
public bool radio4 { get; set; }
public bool radio5 { get; set; }
}
Editor Template:
<div>
<h4>GroupViewModel</h4>
<hr />
<dl class="dl-horizontal">
<dt>#Html.RadioButtonFor(model => model.radio1, true, new { id = Model.GroupName + "1" })</dt>
<dd>#Html.DisplayNameFor(model => model.radio1)</dd>
<dt>#Html.RadioButtonFor(model => model.radio2, true, new { id = Model.GroupName + "2" })</dt>
<dd>#Html.DisplayNameFor(model => model.radio2)</dd>
<dt>#Html.RadioButtonFor(model => model.radio3, true, new { id = Model.GroupName + "3" })</dt>
<dd>#Html.DisplayNameFor(model => model.radio3)</dd>
<dt>#Html.RadioButtonFor(model => model.radio4, true, new { id = Model.GroupName + "4" })</dt>
<dd>#Html.DisplayNameFor(model => model.radio4)</dd>
<dt>#Html.RadioButtonFor(model => model.radio5, true, new { id = Model.GroupName + "5" })</dt>
<dd>#Html.DisplayNameFor(model => model.radio5)</dd>
</dl>
</div>
and the survey View as follows:
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.GroupA)
#Html.EditorFor(m => m.GroupB)
#Html.EditorFor(m => m.GroupC)
<input type="submit" value="Continue" />
}
I have added a group name as posted below, but I could not able to capture the selected value in the http post
#Html.RadioButtonFor(model => model.radio1, true, new { id = Model.GroupName + "1", #Name = Model.GroupName })
You have to override the name attribute:
#Html.RadioButtonFor(model => model.radio1, true, new { id = Model.GroupName + "1", #Name = "Group" })
You have to do this for every radiobutton that you want to have only one selection.
When you use Html.RadioButtonFor it expected that you use the same property to bind all radio buttons like:
#Html.RadioButtonFor(model => model.radio, "answer1")
#Html.RadioButtonFor(model => model.radio, "answer2")
#Html.RadioButtonFor(model => model.radio, "answer3")
Or using an Enumeration in place of "answer1", "answer2" and "answer3"
Each radio button you generating if for a different property and has a different name (they are not grouped) so all radio buttons within a 'Question' can be selected, and worse, none of then can be unselected once selected.
In addition your properties within SurveyViewModel are all the same type, so you should be using a collection property, not generating individual properties for each item.
Start by creating a view model which represents what you want to display/edit in the view.
public class QuestionVM
{
public string Name { get; set; }
[Required(ErrorMesage = "Please select a rating")]
public int? Rating { get; set; }
}
and in the controller GET method
List<QuestionVM> model = new List<QuestionVM>()
{
new QuestionVM() { Name = "A" },
new QuestionVM() { Name = "B" },
new QuestionVM() { Name = "C", Rating = 3 } // use this if you want to pre-select a radio button
};
return View(model);
Next, create an EditorTemplate for QuestionVM. The templates needs to be named /Views/Shared/EditorTemplates/QuestionVM.cshtml
#model QuestionVM
<div class="question">
#Html.HiddenFor(m => m.Name) // so this value posts back
<h2>#Model.Name</h2>
#for(int i = 1; i < 6; i++)
{
<label>
#Html.RadioButtonFor(m => m.Rating, i, new { id = "" })// remove id attribute to prevent invalid html
<span>#i</span>
</label>
}
#Html.ValidationMessageFor(m => m.Rating)
</div>
and finally in the main view
#model IEnumerable<QuestionVM>
#using (Html.BeginForm())
{
#Html.EditorFor(m => m)
<input type="submit" value="Save" />
}
which will post back to
public ActionResult Edit(IEnumerable<QuestionVM model) // adjust method name to suit

How do I use DataAnnotations on Radio Types?

I'm trying to make a form but I have 2 radio buttons which is a required choice if the user wants to complete the registration, but if he/she doesn't select anything, the [Required] DataAnnotation is not working here for some reason.
[Required]
public int UserType { get; set; }
How do I make the form return false with data annotations?
EDIT:
I've changed the model to
[Required(ErrorMessage="Please select an option")]
public int UserType { get; set; }
My view is:
#using (Html.BeginForm("Registrationform", "Members", FormMethod.Post, new { id = "wizardform" }))
{
#Html.ValidationMessageFor(m => m.UserType)
#Html.RadioButtonFor(m => m.UserType, "1", new { #id = "vip_radio"})
#Html.RadioButtonFor(m => m.UserType, "2", new { #id = "normal_radio"})
<input type="submit" value="submit" />
}
when I press submit, the form returns with no errors (it submitted the form) even when I haven't clicked on any of the radio buttons.
I have used like this
Metadata
[Required(ErrorMessage="Please select usertype")]
[Display(Name = "User type")]
public string Usertype{ get; set; }
In view
#Html.RadioButtonFor(model => model.Usertype, "admin", new { id = "admin" })
#Html.Label("admin", "admin", new { style = "padding-right:20px" })
#Html.RadioButtonFor(model => model.Usertype, "employee", new { id = "employee"})
#Html.Label("employee", "employee", new { style = "padding-right:20px" })
works fine for me!
Worked fine for me with below code
$("#MyCheckBox").click(function(){
if($(this).is(':checked')){
$("#vip_radio").rules("add","required")
} else {
$("#normal_radio").rules("remove","required")
}
});

Resources