Fetching Grouped Checkbox in a Controller - c#

I have a checkbox group in a view.
name = "group";
I want to iterate throug this group of checkboxes but I need to find a way to fetch them together;
All selected checkboxes are being posted with their values.
Would I be able to do something like this (one straight statement):
string[] name = Request.QueryString('group');
foreach(string value in name) {
}

The checkboxes are not returned on your query string but rather POSTed to your controller.
Only the selected checkbox values will be returned. To retrieve the entire list of possible checkbox values, you will need to reassemble those from your source.
#foreach (var item in Model.tags)
{
<label>
<input type="checkbox" name="Tag" value="#item.TagID"
#if (item.Selected) { <text>checked="checked"</text> }
/>
#item.Name
</label>
}
[HttpPost]
public RedirectToRouteResult MyAction(IEnumerable<int> Tag)
{
}

andleer's solution will work (with a minor adjustment that I made to his answer and that needs to be approved). However, there is a better way to handle list of checkboxes.
Please see CheckBoxList(For) extension

Related

Default value of DropDownList in an Html.BeginForm block

While a search of "Default value of DropDownList" produces results, this is not a duplicate question because the specific issue is not listed in the examples and answers I have searched.
Here is the main question first, followed by supporting background and details:
When I place a DropdownList in an Html.BeginForm block, how can I have the default DropDownList values be an item other than the first item in the list?
What I have done so far:
SO, Microsoft Virtual Academy, and a general Internet Search using various search terms, with no effective answers that solve this specific issue.
Looking at the overloads of Html.DropDownList on MSDN. The optionLabel parameter inserts an item at the very top of the list, such as "Select an Item", which is not desired behavior.
jQuery, which does work as intended, but I'm really hoping there is a much simpler way that doesn't involve jQuery.
My Working Theory: The method I learned (and shown below) does not allow for default values and it is not a case of not knowing a particular overload of Html.DropDownList.
Background Info:
In the process of learning MVC 5 and gathering instructions from tutorials and SO answers, I learned this style of creating a DropDownList that is placed within a Html.BeginForm() block in the View. It works, if I want the default value to be the first item in the list or if I want to add an item inserted at the top that says "select an item."
However, there are times when it is meaningful to for the default value to be other than the first in the list.
In the controller, the defaults of the parameter are set Index(string campus = "MRA", string fy = "FY16"), and the query returns the correct result, but DropDownLists are not set accordingly when loading the page for the very first time.
Controller
public ActionResult Index(string campus = "MRA", string fy = "FY16")
{
/* The ViewBags feed DropDownLists used to filter the query */
ViewBag.CampusList = new List<string> { "CRA","DRA","MRA","PRA"};
ViewBag.FyList = new List<string> {"FY15","FY16" };
IEnumerable<AssociatedW3SuspensionOrProbation> query =
db.AssociatedW3SuspensionOrProbation
.Where(m=>m.Campus==campus).Where(m=>m.FY==fy)
.OrderBy(m=>m.StudentName).ThenBy(m=>m.LatestEntryDate);
return View(query.ToList());
}
View
The dropdowns function correctly: when the form is submitted, the query results are chosen by the selected dropdown values and the dropdowns load with the selected values.
#using (Html.BeginForm())
{
<div class="panel panel-default">
<div class="panel-body">
<p>
<strong>Campus</strong>: #Html.DropDownList("campus",
new SelectList(ViewBag.CampusList)) ||
<strong>FY</strong>: #Html.DropDownList("fy",
new SelectList(ViewBag.FyList))
</p>
<div><input type="submit" value="Search" /></div>
</div>
</div>
}
Is there a simple answer to this problem, or does this require a totally different approach?
What you have to do is create SelectList in the controller action and there is a constructor overload which can be used to set selected value, but for that you would need a List<T> which is not string but a custom type that contains 2 properties 1 for TextField and 1 for ValueField.
You have to use second Constructor overload listed here
Here is the example code:
ViewBag.CampusList = new SelectList(
new List<string> { "CRA","DRA","MRA","PRA"},
campus // selected value
);
ViewBag.FyList = new SelectList(
new List<string> {"FY15","FY16" },
,fy // selected value
);
and in your view:
#Html.DropDownList("campus",
ViewBag.CampusList as SelectList)
#Html.DropDownList("fy",
ViewBag.FyList as SelectList)

Access the value of Checkboxes from controller - DB

I am trying to make the user update the value of the check box from DB.
The view lists all the available workers in DB.
but when i try to access the list of checkbox, the view passes wrong data
ex. there're only 3 checkbox, and it sends 5 items of true/false value.
I really appreciate any assistance.
View Sample Code
#using (Html.BeginForm("UpdateWorkersForTask", "Tasks", FormMethod.Post))
{
<table>
<tr>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.isChecked)
#Html.CheckBox("WorkersID", item.isChecked)
</tr>
}
and the controler is
[HttpPost]
public ActionResult UpdateWorkersForTask(IEnumerable<bool> WorkersID, IEnumerable<string> hiddens) { }
Because by design #Html.CheckBox and #Html.CheckBoxFor render 2 inputs, a checkbox and a hidden input. If you inspect the html you will see something like
<input name="WorkersID" type="checkbox" value="true">
<input name="WorkersID" type="hidden" value="false">
The reason for this is that unchecked checkboxes do not post back. so the second input ensures a value is posted back. In the case where the checkbox is checked the DefaultModelBinderreads the first value which is true and ignores the second value (because it has the same name).
In your case you are not binding to you model, instead you are just reading all inputs with the name WorkersID. If you have 3 items but 5 values are posted back, it would mean that you checked 2 of the boxes.
To correct this, modify your view and action method as follows (note your model needs to be IList so the for loop works, or alternatively you can use a custom EditorTemplate
View
for(int i = 0; i < Model.Count i++)
{
#Html.CheckBoxFor(m => m[i].WorkersID)
}
Controller
[HttpPost]
ActionResult UpdateWorkersForTask(IEnumerable<YourModelType> model)
{
foreach(YourModelType item in model)
{
// do something with the value of item.WorkersID

Binding a complex model to a drop down list in MVC

I'm trying to bind a model that has two properties - one Int, and one Boolean - to a drop-down list in MVC. The boolean is a discriminator and the integer an ID. It is not possible to split the drop down list in two.
Here is my code so far.
<select class="col-md-3 form-control" name="Model.ID" id="model-select">
<option value="0" selected>Select an Option</option>
#foreach (var m in models.OrderBy(x => x.Id))
{
<option value="#m.ID" data-discriminator="#m.Discriminator">
#m.Name
</option>
}
</select>
The model looks something like this
class MyModel
{
int ID { get; set; }
string Name { get; set; }
boolean Discriminator { get; set; }
}
The aim is to provide a set of models to the View, then the user can pick one of these. Unfortunately each model has two properties which are used to identify which model was selected in the database - the Id, which mirrors the Id in the database, and the Discriminator. The two types are otherwise incompatible in the database, hence the discriminator. For the sake of design, I only want to have these two in the same drop-down list, as you can only select one at a time anyway.
My idea of a solution was to create 2 hidden fields which would be bound to the model like so
<input type="hidden" name="Model.ID" />
<input type="hidden" name="Model.Discriminator" />
These would be updated via JavaScript and then bound to the model (as far as I know, using names like that will bind it correctly, providing that the destination property on the model passed to the POST is Model in this example).
Are there any other alternatives I could pursue?
EDIT: Also worth noting that this 'Model' is part of a more complex model and is not the only field being POSTed, so if that makes any difference...
A select box is only going to be able to post one thing, and using JavaScript to populate hidden fields, while perhaps a workable solution, seems very brittle. Your best bet would like be creating an intermediary property that you can bind to and include both sets of information as the option value:
public string SelectedThing
{
get { return string.Format("{0},{1}", ID, Discriminator); }
set
{
if (value != null)
{
var parts = value.Split(',');
if (parts.Length == 2)
{
Int32.TryParse(parts[0], out ID);
Boolean.TryParse(parts[1], out Discriminator);
}
}
}
}
Then you would need to compose your select list in a similar way:
ViewBag.MyModelChoices = myModels.Select(m => new SelectListItem
{
Value = string.Format("{0},{1}", m.ID, m.Discriminator),
Text = m.Name
});
And finally, you would bind to this new property in your view:
#Html.DropDownListFor(m => m.SelectedThing, ViewBag.MyModelChoices)

How to use grid in VS2010 MVC3 to add and edit data?

I'm using Microsoft VS 2010 C#, MVC3.
I have Calsserooms and Students with many to many relation ship, so I add an intermediat table called Classroom_Students.
When adding students to a classroom, I use a combo box in my view filled with all students names, I choose one by one in every submit
#using (Html.BeginForm("AddStudentToClassroom", "Calssrooms", FormMethod.Post))
{
#Html.LabelFor(c=>c.Students, "Choose a Student")
<select name = "StudentID">
#foreach (var it in Model.Students)
{
<option value="#it.ID">#it.StudentName </option>
}
</select>
<input type="submit" value= "Add" />
}
My question is:
How can I use gride, instead of this combo, to select many students, select all or deselect all to add???
I'll appreciate any help.
This is the code in my controller.
For page first call, I fill combobox as following:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult AddStudentToClassroom(int id) //id of calssroom
{
using (ExaminationEntities en = new ExaminationEntities())
{
ClassroomDetails ClsromView = new ClassroomDetails (); // these are for
ClsromView.Classroom = en.Classroom.Single(c => c.ID == id);// loading calssroom information and to
ClsromView.Students = en.Students.ToList(); // fill students list for the combobox
return View(ClsromView);
}
}
When submiting the form, view, and click the add button, it calls the following overloaded add function for saving data:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddStudentToClassroom(AddStudToCals ClasStud) //ClasStud is the submited data from the view
{
using (ExaminationEntities en = new ExaminationEntities())
{
ClassroomDetails ClsromView = new ClassroomDetails(); // these are for
ClsromView.Calssroom = en.Calssroom.Single(c => c.ID == ClasStud.ClassroomID); // loading calssroom information and to
ClsromView.Students = en.Student.ToList(); // fill students list for the combobox
using (ExaminationEntities exn = new ExaminationEntities())
{
Calssroom_Student To_DB_ClasStud = new Calssroom_Student (); //To_DB_ClasStud object to get the submited values and to save it in the DB
To_DB_ClasStud.CalssroomID = ClasStud.CalssroomID;
To_DB_ClasStud.StudentID = ClasStud.StdentID;
en.AddToClassroom_Student(To_DB_ClasStud);
en.SaveChanges();
}
return View(ClsromView);
}
}
Well, the option that requires the least changes to your markup is to add the multiple property to your select. Then, change the action method to accept a params int[] ids, iterate through them, and you should be good-to-go. At worst, you might have to change your parameter to a string and do a Split() on ,, but I don't recall that being how the model binder supports multi-selects.
If this doesn't seem to fit your needs, there is an article on the ASP.NET website that explains using a MultiSelectList to bind to the ListBox helper, here:
http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and-jquery/using-the-dropdownlist-helper-with-aspnet-mvc

Edit View with child entity selection listbox and HTTPPost difficulties

I have a Search Edit view which is strongly typed to my Search model class seen below (simplified).
I want to display the custodians that are attributed to the Search being edited in a listbox showing all Custodians, with the current ones selected.
My controller's Get Edit action is thus:
public ActionResult Edit(int id, int searchListId = 0)
{
if (searchListId != 0)
{
Session["CurrentSearchListID"] = searchListId;
}
ProjectContext mydb = db;
Search search = Search.Find(mydb, id);
IEnumerable<SelectListItem> selectedItems =
from c in Custodian.List(mydb)
select new SelectListItem
{
Selected = (search.Custodians.Contains(c)),
Text = c.CustodianName,
Value = c.ToString()
};
ViewBag.Custodians = selectedItems;
return View(search);
}
And my Views listbox is thus:
#{
//List<Kiersted.Keps.BusinessObjects.Custodian> Custodians = ViewBag.Custodians;
IEnumerable<SelectListItem> SelectedItems = ViewBag.Custodians;
}
#Html.ListBox("Custodians", SelectedItems);
This produces a listbox with the Custodians depicted, but none are selected (I have confirmed that several of the SelectListItems accurately describe the custodian as selected. I have tried using ListBoxFor and it produces the same thing when populated with a MultiSelectList.
Finally I decided to just force it to do what I want, but this does not return selected Custodians on Submit.
<select id="Custodians" multiple="multiple" name="Custodians">
#foreach (Kiersted.Keps.BusinessObjects.Custodian cust in Custodians)
{
if (Model.Custodians.Contains(cust))
{
<option value="#cust.CustodianID" selected="selected">#cust.CustodianName</option>
}
else
{
<option value="#cust.CustodianID" >#cust.CustodianName</option>
}
}
</select>
Anyone know how you are supposed to do this?
Edits:
ListBoxFor example
OK so after fiddling around with it for a while longer, I have now gotten Custodians selected in the listbox that correspond to the Search Custodians. Below is the view code:
<div class="editor-field">
#Html.ListBoxFor(model => model.Custodians, allCustodians.Select(cust => new SelectListItem {
Text = cust.CustodianName,
Value = cust.CustodianID.ToString(),
Selected = true}),
new { Multiple = "multiple" })
</div>
If I select several more custodians, how do I get them (or their corresponding values rather) back to the control upon submit?
Seeing that after your edit the problem boils down to multiple select model binding, perhaps you will find these useful?
How does a multiple select list work with model binding in ASP.NET MVC?
http://ittecture.wordpress.com/2009/04/30/tip-of-the-day-198-asp-net-mvc-listbox-controls/

Categories