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
Related
So, I am trying to create a multi-select dropdown list and I want to set some default selected values in it. I get the values and store them in an array of strings containing the values in each one. I tried to set them as 1 string and it didn't work, tried setting them as an array of strings and it didn't work as well.
Here is the code:
<select name="FacultyList" multiple class="sel form-control" asp-for="Faculties"
id="uniFaculties" asp-items="#(new SelectList(facultyList,"Name","Name",#selectedFaculties))">
</select>
facultyList is a list of values I get from and api.
selectedFaculties is an array of strings that contains the selected values.
Note: I'm using the Chosen jQuery library as well if that makes a difference.
There is a MultiSelectList that you can use for this:
new MultiSelectList(facultyList, "Name", "Name", #selectedFaculties)
I just noticed from your code that you're using asp-for on the select. When doing that, the selected values you pass to either SelectList or MultiSelectList will be ignored. The reason is because it's expecting the selected values to be in the Faculties property that you're binding to. In case you run into that, here is a working example for you.
View
<select name="FacultyList" multiple class="sel form-control" asp-for="SelectedFaculties"
id="uniFaculties" asp-items="#(new MultiSelectList(Model.AvailableFaculties, "Name", "Name"))">
</select>
Controller
public IActionResult Faculty()
{
var vm = new FacultyViewModel
{
AvailableFaculties = new List<Faculty>
{
new Faculty
{
Name = "Arts"
},
new Faculty
{
Name = "Science"
},
new Faculty
{
Name = "Mathematics"
}
},
SelectedFaculties = new List<string> { "Arts", "Mathematics" }
};
return View(vm);
}
This will select Arts and Mathematics. Notice that the selected values are coming from the same property that we're binding the select to using asp-for, and that we're no longer passing selected values to the MultiSelectList directly.
I am trying to add records from table position for positionName(s) to let user select a position for employee when editing.My last attempts is to add a navigation property like field in company model
public virtual ICollection<Position> Mpositions { get; set; }
But all I got so far is null ref exception or no element in viewModel with property "PositionName" ass per viewbag didn't bother using everybody keeps recommending to avoid it so not going to do so either.
public ActionResult Edit([Bind(Include = "CompanyID,CompanyName,EntityForm,Address,Dissolute,CreationDate,FiscaleYear,Description")] Company company)
{
var GlbUpdate = db.Companies.Include(c => c.Members).Include(p => p.Mpositions);
List<Company> mdlCompanies = new List<Company>();
foreach (var item in GlbUpdate)
{
if ((item.Mpositions==null) || (item.Mpositions.Count() == 0))
{
item.Mpositions = (ICollection<Position>)new SelectList(db.Positions.Except((IQueryable<Position>)db.Positions.Select(xk => xk.Members)), "PositionID", "PositionName");
}
mdlCompanies.Add(item);
//I tried first to edit the Mpositions property directly in gblUpdate
//item.Mpositions = (IEnumerable<Position>)db.Positions.Select(p => new SelectListItem { Value = p.PositionID.ToString(), Text = p.PositionName}) ;
//(ICollection<Position>)db.Positions.ToListAsync();
}
In the view I have this
List<SelectListItem> mPositionNames = new List<SelectListItem>();
#*#this yields no results if I try gettign it from the compani record itself it gives a logic error where all id match all positionNames impossible to select an item and only positions already registered are available on the dropDownlist*#
#{foreach (var item in Model.Mpositions)
{
mPositionNames.Add(new SelectListItem() { Text = item.PositionName, Value = item.PositionID.ToString(), Selected = (false) ? true : false });
#*#selected attribute set to false not an issue, no data to select from :p so far*#
}
}
#*#null exception(if i try to midify Mpositions directly in controler) here or empty list if modify it then put it with original query in a new list*#
<div class="SectionContainer R-sectionContainerData" id="MwrapperDataRight">
#Html.DropDownListFor(mpos => item.PositionID, (SelectList)Model.Mpositions)
</div>
All I want to do is pull the positions table to create a drop downList so users can change the position of an employee but since position has a 1>many relation with employee not companies it is not bound automatically by EF nor I seem to be able to use Include() to add it.
Your query for editing positions are complex. This query must edit person's info only. Using Edit action for formalizing position's edit are not correct.It's againts to Single Responsibility Principle. Use ViewComponents for this situation. Load positions separately from person info.
I found a suitable solution using a model that encapsulate the other entities then using Partialviews/RenderAction so each part handles one entity/operation.
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)
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/
I'm trying to set up a page where I display a list of items and the details of the selected item. I have it working but wonder whether I have followed the correct approach. I'll use customers as an example
I have set the aspx page to inherit from an IEnumerable of Customers. This seems to be the standard approach to display the list of items. For the Details I have added a Customer user control which inherits from customer.
I think i'm on the right track so far but I was a bit confused as to where I should store the id of the customer whose details I intend to display. I wanted to make the id optional in the controller action so that the page could be hit using "/customers" or "customers/1" so I made the arg optional and stored the id in the ViewData like this:
public ActionResult Customers(string id = "0")
{
Models.DBContext db = new Models.DBContext();
var cList = db.Customers.OrderByDescending(c => c.CustomerNumber);
if (id == "0")
{
ViewData["CustomerNumber"] = cList.First().CustomerNumber.ToString();
}
else
{
ViewData["CustomerNumber"] = id;
}
return View("Customers", cList);
}
I then rendered the User control using RenderPartial in the front end:
<%var CustomerList = from x in Model
where x.CustomerNumber == Convert.ToInt32(ViewData["CustomerNumber"])
select x;
Customer c = (Customer)CustomerList.First(); %>
<% Html.RenderPartial("Customer",c); %>
Then I just have an actionLink on each listed item:
<%: Html.ActionLink("Select", "Customers", new { id = item.CustomerNumber })%>
It all seems to work but as MVC is new to me I would just be interested in others thoughts on whether this is a good approach?
In regards to proper MVC and separations of concerns, you shouldn't be calling LINQ queries in your view. To get around that, change your controller action code from what you have to this:
if (id == "0")
{
ViewData["CustomerDetails"] = cList.First();
}
else
{
ViewData["CustomerDetails"] = From x in db.customers where x.id = cInt(id);
}
then your partial
<% Html.RenderPartial("Customer",ViewData["CustomerDetails"]); %>
Are you showing the customer information on the same screen that you have your list of customers and not a separate view?
In this case I would take the following approach.
Display a list of customer's, be it a listbox or drop down list.
Let's assume it's a drop down list, probably not very user friendly
You would have the text as the customer name and then the value as the customer id
<select title="Customers">
<option label="Pieter" value="001"></option>
</select>
and using JQuery's $.getJSON you could load the new data via a call to an asp.net MVC action.
Note that your Action should return JsonResult