MVC and Entity Framework Select List - asp.net

I have an MVC app that I am trying to put together that requires some select lists and drop down lists.
So, I have the following models....
public class Task
{
public int ID { get; set; }
public string Title { get; set; }
......
public virtual ICollection<Monitor> Monitors { get; set; }
public virtual ICollection<Resource> Resources { get; set; }
}
public class Monitor
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<Task> Tasks { get; set; }
}
public class Resource
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
.....
public IList<Task> Tasks { get; set; }
The interesting part is that when I display a list of tasks, among the other properties that display just fine, I need to display a list of 'Monitors' and a list of 'Resources' that are assigned to the task in the Index view shown below.
#model IEnumerable<ResourceManager.Models.Task>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
.....
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
.....
<th>
#Html.DisplayNameFor(model => model.Monitors)
</th>
<th>
#Html.DisplayNameFor(model => model.Resources)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
.....
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
.....
<td>
#if (item.Monitors == null || item.Monitors.Count == 0)
{<span>No Monitors Assigned</span>}
else
{ string.Join(", ", item.Monitors.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName))); }
</td>
<td>
#Html.DisplayFor(modelItem => item.Resources)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
And here is the controller....
public ActionResult Index()
{
var tasks = from t in db.Tasks where t.IsActive == true select t;
return View(tasks);
}
I would like for the list of Monitors and the list of Resources to display as a string on the Index, Delete and Details Views i.e. 'Monitor 1, Monitor 2, Monitor 3' and 'Resource 1, Resource 2, Resource 3'.
However on the other views (Create and Edit), I want them to appear as a selectable list.

First Create Select list in your controller,
var monitors = //Your linq query
ViewData["ddlList"] = monitors .Select(x => new SelectListItem {
Text = x.FirstName,
Value = x.Id.ToString()
}).ToList();
And then you can use it in your view as follows,
<%=Html.DropDownList("myList") %>

For the display of Monitors/Resources (and since you want them displayed as a comma-delimited list), you can just use string.Join:
<td>
#string.Join(",", Model.Monitors.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName)))
</td>
To be able to actually use Html.DisplayFor, you'd have to create a custom display template so Razor will actually know how to respond. To do so, in your Views folder, create new folder called "DisplayTemplates", and in that, create a new partial view called "Monitors.cshtml" and "Resources.cshtml", strongly-typed to IEnumerable<Monitor> and IEnumerable<Resource>, respectively. Then inside that file, you'll just add roughly the same code as above:
#model IEnumerable<Monitor>
#string.Join(",", Model.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName)))
Then in your view, you can call:
#Html.DisplayFor(m => m.Monitors, "Monitors")
Unfortunately, in this example, you'd have to feed the template name because the default behavior of DisplayFor for a list, is to render the display template multiple times, once for each member of the list. You could do something like:
# Monitor.cshtml
#model Monitor
#Model.FirstName #Model.LastName,
And then:
#Html.DisplayFor(m => m.Monitors)
But your last item would have a comma at the end.
For editing the lists, all you have to do is pass the select lists to your view. Optimally, you'd do this with a view model, but for simplicity's sake, I'll just use ViewBag here. In your controller action:
ViewBag.MonitorChoices = db.Monitors.Select(m => new SelectListItem
{
Value = m.ID.ToString(),
Text = string.Format("{0} {1}", m.FirstName, m.LastName)
});
Then, in your create/edit view:
#Html.ListBoxFor(m => m.Monitors, ViewBag.MonitorChoices)

Try as follows,
var monitors = //Your linq query
List monitorList = new List();
foreach (var monitor in monitors ){
SelectListItem item = new SelectListItem();
item.Text = monitor.FirstName;
item.Value = monitor.Id.ToString();
monitorList .Add(item);
}
ViewData["ddlList"] = monitorList;

Related

How to take value from Select/Option and inserted into href

I need help if it is possible. I have a list of classrooms, as it is in the picture below. I want to list all teachers in the "select option" and when the user selects the teacher he can click save and the classroom will be updated, as it is in the href. How can I take the value after the foreach loop?
<select id="teachers">
#foreach(var teacher in #Model.Teachers){
<option value="#teacher.Id">#teacher.Id</option>
}
</select>
<a asp-controller="Classroom" asp-action="Update" asp-route-teacherId=""></a>
<a asp-controller="Classroom" asp-action="Update" asp-route-teacherId="XX">Save</a>
First, for the above a tag helper, the generated HTML like this:
Save
or
Save
Besides, to update teachers in specific classrooms, you should also submit the classroom id to the Update action method, so, the generated URL should have multiple parameters(teacherid and classroomId), like this: Save
More detail information, see Anchor Tag Helper.
I have a list of classrooms, as it is in the picture below. I want to
list all teachers in the "select option" and when the user selects the
teacher he can click save and the classroom will be updated, as it is
in the href. How can I take the value after the foreach loop?
From your description, each classroom (row) should have a <select> element to choose the teacher and a "Save" button to update the current row update, right?
In this scenario, you could use the select element's change event to get the selected value, and then update the <a> tag href attribute.
You can refer the following sample:
Model:
public class ClassRoom
{
public int ID { get; set; }
public string Classroom { get; set; }
public string SubJect { get; set; }
public string Teacher { get; set; }
public DateTime Date { get; set; }
}
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Subject
{
public int Id { get; set; }
public string SubjectName { get; set; }
}
public class ClassRoomViewModel
{
public List<ClassRoom> ClassRooms { get; set; }
public List<Teacher> Teachers { get; set; }
public List<Subject> Subjects { get; set; }
}
Controller:
public class ClassRoomController : Controller
{
public IActionResult Index()
{
// you could query the database to get the data. The following is the test data.
var viewmodel = new ClassRoomViewModel();
viewmodel.ClassRooms = new List<ClassRoom>()
{
new ClassRoom(){ ID=1, Classroom="EOIS1", Date=DateTime.Now },
new ClassRoom(){ ID=2, Classroom="EOIS2", Date=DateTime.Now }
};
viewmodel.Teachers = new List<Teacher>()
{
new Teacher(){ Id=101, Name="Tom"},
new Teacher(){ Id=102, Name="Jack"}
};
return View(viewmodel);
}
public IActionResult Update(int teacherId, int classroomid)
{
//update the classroom
//redirect to the Index page and refresh the page.
return RedirectToAction(nameof(Index));
}
}
View Page:
#model MVCWebApplication.Models.ClassRoomViewModel
<table class="table" id="customers" >
<thead>
...
</thead>
<tbody>
#foreach (var item in Model.ClassRooms) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Classroom)
</td>
<td>
#Html.DisplayFor(modelItem => item.SubJect)
</td>
<td>
<select id="teachers" class="teachers">
<option value="0">select teacher</option>
#foreach (var teacher in #Model.Teachers)
{
<option value="#teacher.Id">#teacher.Name</option>
}
</select>
</td>
<td>
<a asp-controller="ClassRoom" asp-action="Update" asp-route-classroomid="#item.ID" asp-route-teacherId="">Save</a>
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
</tr>
}
</tbody>
</table>
#section Scripts{
<script>
$(function () {
$(".teachers").each(function (Index, item) {
$(item).change(function () {
var teacherid = $(this).val(); //get the selected value.
var existinghref = $(item).parent().parent().find("a").attr("href"); //get the hyperlink href attribute.
if (teacherid != 0) {
existinghref = existinghref + "&teacherId=" + teacherid; //add the parameter at the end of the request url.
$(item).parent().parent().find("a").attr("href", existinghref); //update the hyperlink href attribute.
}
else {
alert("Please select teacher"); //show prompt to let user select teacher.
}
});
});
});
</script>
}
The result as below:

Using checkboxes to filter table by boolean columns in MVC 5

I want to be able to filter the contents of my "Contacts" table by interests, and I am currently attempting to accomplish this through a series of Boolean properties representing each individual interest. The plan was that I was going to have a series of checkboxes on the Index page for each Interest that would allow the user to display only Contacts that had one or more of the appropriate Interest variables set to "true" for each checkbox that was checked (or all Contacts if no checkboxes were selected). As far as I can tell this is theoretically possible, but my research so far has not turned up any results as to how to perform this sort of filtering in this specific manner. Could anyone here perhaps point me in the right direction?
EDIT: Here is what code I have so far related to the problem:
EDIT2: I have a nominally working set of checkboxes in place, but now the filtering isn't working quite the way I want it to. I want the controller to send the view only whichever Contacts have one or more of the same variables set to "true" as the appropriate checked boxes, or all Contacts if no boxes are checked. What I have now works fine for single selections, but with multiple selections only returns entries that match all checked boxes. I would like to know how to conditionally filter more effectively and efficiently than what I have now.
Here is my model- the "Interests" string was just to make it more presentable in the Index than just a line of grayed-out checkboxes:
public class Contact : IValidatableObject
{
public int Id { get; set; }
public string Email { get; set; }
public string PhoneNum { get; set; }
public string Name { get; set; }
public bool LikesClassic { get; set; }
public bool LikesCountry { get; set; }
public bool LikesHipHop { get; set; }
public bool LikesMetal { get; set; }
public bool LikesPop { get; set; }
public bool LikesRap { get; set; }
public bool LikesRock { get; set; }
public string Interests
{
get
{
var interests = "";
if (this.LikesClassic)
interests = interests + "[Classic] ";
if (this.LikesCountry)
interests = interests + "[Country] ";
if (this.LikesHipHop)
interests = interests + "[Hip-Hop] ";
if (this.LikesMetal)
interests = interests + "[Metal] ";
if (this.LikesPop)
interests = interests + "[Pop] ";
if (this.LikesRap)
interests = interests + "[Rap] ";
if (this.LikesClassic)
interests = interests + "[Rock] ";
return interests;
}
}
Here is my View- the checkboxes are in place but not yet functional
#model IEnumerable<ContactInterests.Models.Contact>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm())
{
<p>
Classic: #Html.CheckBox("Classic")
Country: #Html.CheckBox("Country")
Hip-Hop: #Html.CheckBox("HipHop")
Metal: #Html.CheckBox("Metal")
Pop: #Html.CheckBox("Pop")
Rap: #Html.CheckBox("Rap")
Rock: #Html.CheckBox("Rock")
<input type="submit" value="Search" />
</p>
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.PhoneNum)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
Interests
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.PhoneNum)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Interests)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
Here is my Index ActionResult for my Contacts controller; again, it is crude but nominally functional, just not in the way I would have preferred:
public ActionResult Index(string Classic, string Country, string HipHop,
string Metal, string Pop, string Rap, string Rock)
{
var contactList = from c in db.Contacts select c;
if (Classic == "true")
{
contactList = contactList.Where(c => c.LikesClassic == true);
}
if (Country == "true")
{
contactList = contactList.Where(c => c.LikesCountry == true);
}
if (HipHop == "true")
{
contactList = contactList.Where(c => c.LikesHipHop == true);
}
if (Metal == "true")
{
contactList = contactList.Where(c => c.LikesMetal == true);
}
if (Pop == "true")
{
contactList = contactList.Where(c => c.LikesPop == true);
}
if (Rap == "true")
{
contactList = contactList.Where(c => c.LikesRap == true);
}
if (Rock == "true")
{
contactList = contactList.Where(c => c.LikesRock == true);
}
if (Classic == "false" && Country == "false" && HipHop == "false" && Metal == "false" && Pop == "false" && Rap == "false" && Rock == "false")
{
contactList = from c in db.Contacts select c;
}
return View(contactList.ToList());
}

Model not valid when navigational property is null

I am new to ASP mvc and entity framework
I have a model created by entity framework as
public partial class Privilege
{
public Privilege()
{
this.Role_Privilege_Map = new HashSet<Role_Privilege_Map>();
}
public int PrivilegeId { get; set; }
[Required(ErrorMessage="*")]
[Display(Name = "Privilege Name")]
public string PrivilegeName { get; set; }
[Required(ErrorMessage = "*")]
public Nullable<int> ModuleId { get; set; }
public virtual module module { get; set; }
public virtual ICollection<Role_Privilege_Map> Role_Privilege_Map { get; set; }
}
As you can see module is a navigational property.
I have binded this model to a view as
#for (var i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => modelItem[i].PrivilegeName)
#Html.HiddenFor(modelItem => modelItem[i].PrivilegeId)
#Html.HiddenFor(modelItem => modelItem[i].PrivilegeName)
</td>
<td>
#Html.DisplayFor(modelItem => modelItem[i].module.ModuleName)
#Html.HiddenFor(modelItem => modelItem[i].ModuleId)
#Html.HiddenFor(modelItem => modelItem[i].module.ModuleName)
#Html.HiddenFor(modelItem => modelItem[i].module)
</td>
<td>
#Html.CheckBoxFor(modelItem => modelItem[i].Checked)
#Html.HiddenFor(modelItem => modelItem[i].Checked)
</td>
<td>
#Html.ActionLink("Edit", "OpenEditPrivilegeDialog", "RolePrivilegeMapping",
new { id = Model[i].PrivilegeId },
new { #class = "actionHyperLink edit_Privilege_Link" }) |
#Html.ActionLink("Delete", "DeletePrivilege","RolePrivilegeMapping",
new { id = Model[i].PrivilegeId },
new { #class = "actionHyperLink Delete_Privilege_Link" })
</td>
</tr>
}
I have an Update button for updating this model say Privilege name. Now in my action
public ActionResult UpdateRolePrivilege(IList<One_Track.Models.Privilege> updatedPrivilege)
{
if (ModelState.IsValid)
{
}
else
{
ViewBag.PrivilegeMessage = "Privileges updation Failed.";
}
}
return PartialView("PrivilegePartial", sample.GetPrivilegeNames());
}
Is returning false. I put a breakpoint and come to know that the navigational property is null that could be a reason for model not been valid. How can I surpass this. As you can see in code I have added a hidden field for binding navigational property
Why is this happening? Any help will be appreciated
As per the post ModelState.IsValid == false, why? provided by wiz kid
I come to know that tan exception is occuring there as
The parameter conversion from type 'System.String' to type 'sample.Models.module' failed because no type converter can convert between these types.
at System.Web.Mvc.ValueProviderResult.ConvertSimpleType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.UnwrapPossibleArrayType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.ConvertTo(Type type, CultureInfo culture)
at System.Web.Mvc.DefaultModelBinder.ConvertProviderResult(ModelStateDictionary modelState, String modelStateKey, ValueProviderResult valueProviderResult, Type destinationType)}
So I removed the line from view
#Html.HiddenFor(modelItem => modelItem[i].module)
This solved by problem

Radio button list using editor templates for merging contacts

I am trying to display a form for merging two contacts in ASP.net MVC 5.
The form should look like this where each row holds a radio button group consisting of 2 options:
The form shows up just fine, and the radio groups work (I can select each group). However, when the model is posted back to the server, the Values list is empty (not preserved). I would like to get both the selected id but of course also the actual text value back in the controller. I prefer to do this using Editor Templates and if possible without for loops.
The current results (Values = null):
EDIT to respond to comments: I would prefer not to re-fetch the values in the controller again, because it results in a call to a web service. I have tried some variants of HiddenFor without results.
My models look like this:
public class Contact
{
public List<ContactRow> Rows { get; set; }
public Contact()
{
this.Rows = new List<ContactRow>();
this.Rows.Add(new ContactRow("First Name", "Homer", "Homie"));
this.Rows.Add(new ContactRow("Last Name", "Simpson", "Simson"));
this.Rows.Add(new ContactRow("Email", "mail1", "mail2"));
this.Rows.Add(new ContactRow("Company Phone", "Phone1", "Phone2"));
this.Rows.Add(new ContactRow("Mobile Phone", "Mobile1", "Mobile2"));
}
}
public class ContactRow
{
public int Selection { get; set; }
public string Label { get; set; }
public List<ValueSet> Values { get; set; }
public ContactRow(string Label, string LeftValue, string RightValue, int Selection = 0)
{
if (LeftValue== null) LeftValue= "";
if (RightValue== null) RightValue= "";
this.Label = Label;
this.Selection = Selection;
this.Values = new List<ValueSet>(2);
this.Values.Add(new ValueSet() { ID = 0, ValueText = LeftValue});
this.Values.Add(new ValueSet() { ID = 1, ValueText = RightValue});
}
public ContactRow() { }
}
public class ValueSet
{
public int ID { set; get; }
public string ValueText { set; get; }
}
The Controller:
public ActionResult Index()
{
Contact model = new Contact();
return View(model);
}
public ActionResult MergeContacts(Contact model)
{
return RedirectToAction("Index");
}
And the views:
Index.cshtml
#model RadioTest.Models.Contact
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm("MergeContacts", "Home", FormMethod.Post, new { encType = "multipart/form-data", id = "contactDetailsForm", name = "contactDetailsForm" }))
{
<div>
<table class="table" width="100%">
<tr>
<th style="text-align:left">Label</th>
#*<th style="text-align:right">R1</th>*#
<th style="text-align:left">
Left Value
</th>
#*<th style="text-align:right">R2</th>*#
<th style="text-align:left">
Right Value
</th>
</tr>
#Html.EditorFor(model => model.Rows)
</table>
<input type="submit" />
</div>
}
Editor Template for ContactRow:
ContactRow.cshtml
#model RadioTest.Models.ContactRow
<tr>
<td style="text-align:left">
#Html.DisplayFor(model => model.Label)
</td>
#foreach (var v in Model.Values)
{
<td style="text-align:left">
#Html.RadioButtonFor(model => model.Selection, v.ID) #v.ValueText
</td>
}
</tr>
#Html.HiddenFor(model => model.Label)
Just change your foreach to for:
#model MVCApp.Controllers.ContactRow
<tr>
<td style="text-align:left">
#Html.DisplayFor(model => model.Label)
</td>
#for (int i = 0; i < Model.Values.Count; i++)
{
<td style="text-align:left">
#Html.RadioButtonFor(model => model.Selection, Model.Values[i].ID) #Model.Values[i].ValueText
#Html.HiddenFor(model => Model.Values[i].ID)
#Html.HiddenFor(model => Model.Values[i].ValueText)
</td>
}
</tr>
#Html.HiddenFor(model => model.Label)

Pass a model to an MVCMailer view

I have a controller, which passes a model (ovw.ToList()) to a view:
//
// GET: /Clinic/Overview/
public ActionResult Overview()
{
IEnumerable<Clinic> ovw = from c in db.Clinics
select c;
return View(ovw.ToList());
}
View:
#model IEnumerable<ttp.Models.Clinic>
#foreach (var item in Model)
{
<div>#item.ClinicName</div>
#foreach (var item2 in item.Properties)
{
<div>#item2.Address</div>
This works absolutely fine on screen.
When using MVCMailer, however , if I want to display the same layout in the email, how do I pass the ovw.ToList() to the mailer view, so that I can reference the same model in this way:
(I'm stuck on what to put in as the first line in the view):
#model IEnumerable<ttp.Models.Clinic>
#foreach (var item in Model)
Thanks for any help,
Mark
You should find your answer in the 'Pass Data to Mailer Views' part of this guide: https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
To pass your model along with the view to MVCMailer, you need to use ViewData:
var comment = new Comment {From = me, To = you, Message = "Great Work!"};
ViewData = new ViewDataDictionary(comment);
In my project i doing like this it's below
i am showing all my category list in my index view
in my model class
public List<CategoryDetails> CategoryData { get; set; }
and i am also create CategoryDetails class and create a property to all my field
like this
public int CatID { get; set; }
[Required(ErrorMessage = "Enter Category Name")]
public string CatName { get; set; }
public string CatImage { get; set; }
and create a function in my main model class like this
public void LoadCategory()
{
CategoryData = (from con in dbData.Categorys
select new CategoryDetails()
{
CatID = con.CatID,
CatName = con.CatName,
CatImage = con.CatImage,
}).ToList();
}
In my controller i create a action like this
create my model class object and pass my model function to action
public ActionResult Index()
{
CategoryModel categorymodel = new CategoryModel();
categorymodel.LoadCategory();
return View(categorymodel);
}
and in my view
#model PMS.Models.CategoryModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Category Name
</th>
<th>
</th>
</tr>
#foreach (var item in Model.CategoryData)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CatName)
</td>
</tr>
}
</table>
i think this will help you

Resources