Maybe (actually I'm sure) it's me, but I cannot seem to figure out how to retrieve list items as part of a model object. The post here seems to satisfy everyone but neither answer is relatable in my limited understanding.
I need to get the items that are checked so I can update the Db. Sounds simple.
My Model:
public class UserAdminModel
{
public Guid UserId { get; set; }
public string UserName { get; set; }
public List<UserRole> UserRoles { get; set; }
public string csvAllRolls { get; set; }
}
public class UserRole
{
public Guid RoleId { get; set; }
public string UserRoleName { get; set; }
public bool UserisinRole { get; set; }
}
My View:
<% using (Html.BeginForm("UpdateRoles", "UserAdmin", FormMethod.Post))
{%>
<input type="hidden" id="UserId" name="UserId" value="<%: Model.UserId %>" />
...
<% foreach (var role in Model.UserRoles)
{ %>
<tr>
<td> </td>
<td colspan="2" nowrap="nowrap"><%: role.UserRoleName %></td>
<td> </td>
<td>
<input type="checkbox" id="UserRoles" name="UserRoles" value="<%: role.UserRoleName %>"
<% if (role.UserisinRole) { %>
checked="checked"
<% } %>
/></td>
</tr>
<% } %>
...
<input type="submit" name="Submit" value="Update Roles" /></td>
<% } %>
My Controller:
[HttpPost]
public ActionResult UpdateAllRoles(UserAdminModel model)
{
Guid uid = new Guid( Request["UserId"]);
return RedirectToAction("Index", "MyController");
}
The UserId comes through fine but the rest of the model is null. Any help would be appreciated.
You need to use a for loop so that your form controls have the correct name attributes to bind to your model (I'll leave it to you to convert from razor to aspx)
#using (Html.BeginForm("UpdateRoles", "UserAdmin", FormMethod.Post))
{
#Html.HiddenFor(m => m.UserId) // or add this as a route parameter in BeginForm()
...
for(int i = 0; i < Model.UserRoles.Count; i++)
{
#Html.HiddenFor(m => m.UserRoles[i].RoleId)
#Html.CheckBoxFor(m => m.UserRoles[i].UserisinRole)
#Html.LabelFor(m => m.UserRoles[i].UserisinRole, Model.UserRoles[i].UserRoleName)
}
<input type="submit" name="Submit" value="Update Roles" />
}
When you submit the form, model.UserRoles will contain all roles and you can get the selected roles using
var selectedRoles = model.UserRoles.Where(r => r.UserisinRole);
Side note: Using a <table> does not seem appropriate here.
Related
I have a view where I displayed all the records from Requests table. Every record has a save and remove button, so the user can add or remove a request to/from ReqHistory table.
How can I get the data (ID, Title, Description .etc) of each record, from the request view, and pass it to my add/remove actions in ReqHistoryController?
When I submit the form, it won't take the data of the record from the view.
Can anybody help me?
#model IEnumerable<App.Models.Request>
#foreach (var item in Model)
{
<form asp-action="AddReqToHistory" asp-controller="ReqHistory">
<div class="card border-dark mb-3" style="max-width: 30rem;">
<div class="card-header">
#item.Title
</div>
<div class="card-body text-dark">
<img class="imageThumbnail" src="~/images/#item.ImagePath" asp-append-version="true" alt="image" />
<p class="card-text">
<br />
#item.Description
</p>
<a asp-action="Details" asp-route-id="#item.ID" >
Details
</a>
<input asp-action="AddReqToHistory" asp-controller="ReqHistory" type="submit" value="Save" />
<input asp-action="EliminateReqFromHistory" asp-controller="ReqHistory" type="submit" value="Eliminate" />
</div>
</div>
</form>
}
Here are the two actions from ReqHistoryController:
public async Task<IActionResult> AddReqToHistory([Bind("ID, Title,Description,ImagePath")] Request model)
{
var currentUser = await _userManager.GetUserAsync(User);
var userId = await _userManager.GetUserIdAsync(currentUser);
var newReqHistory = new ReqHistory()
{
UserId = userId,
RequestId = model.ID,
Title = model.Title,
Description = model.Description,
CategoryID = model.CategoryID,
PersonID = model.PersonID,
ImagePath = model.ImagePath
};
_context.Add(newReqHistory);
await _context.SaveChangesAsync();
return RedirectToAction("Index", "Requests");
}
// POST
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EliminateReqFromHistory(int requestId)
{
var reqHistory = await _context.ReqHistory.FindAsync(_userManager.GetUserId(User), requestId); //ReqHistory has a composite PK
_context.ReqHistory.Remove(reqHistory);
await _context.SaveChangesAsync();
return RedirectToAction("Index", "Requests");
}
ReqHistory model class:
public class ReqHistory
{
[Key]
public string UserId { get; set; }
[Key]
public int RequestId { get; set; }
public ICollection<Request> Requests { get; set; } //1-M relationship
public string Title { get; set; }
public string Description { get; set; }
public string ImagePath { get; set; }
//one-to-one relationship
public int CategoryID { get; set; }
public Category Category { get; set; }
public int PersonID { get; set; } //FK
public Person Person { get; set; } //nav property
}
Here is the ReqHistory view:
#model IEnumerable<App.Models.ReqHistory>
<table class="table table-condensed table-bordered">
<tr>
<th>
#Html.DisplayNameFor(model => model.RequestId)
</th>
<th>
#Html.DisplayNameFor(model => model.UserId)
</th>
...........................
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#item.RequestId
</td>
<td>
#item.UserId
</td>
..................
</tr>
}
</table>
<a asp-action="AddReqToHistory" asp-controller="ReqHistory" type="submit" value="Save" asp-route-HEREID="#model.ID" />
<a asp-action="EliminateReqFromHistory" asp-controller="ReqHistory" type="submit" value="Eliminate" asp-route-HEREID="#model.ID" />
you can pass id through asp-route by url method.
Scenario
I am going to create a simple interface to insert donations from students using Asp.net Core MVC and EF. According to the App, before entering donation I have to display student information (from Student table) by using student's Admission number (Add_No).
Then I have to insert donation data using the same view but using a different submit button to the table Welfare.
Problem:
I tried it as following ways as shown in my code blocks. Insertion is successful. But I couldn't show student info on the screen even though I retrieve them.
Code for View.cshtml
#model Student_Management.Models.Welfare
#{
ViewData["Title"] = "Wcreate";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h4 align="center">Welfare Donation Entry Form</h4>
<hr />
<table>
<tr>
<td>
#using (Html.BeginForm("getStudentInfo", "Payments", FormMethod.Post))
{
<div class="form-group">
<label asp-for="Add_No" class="control-label"></label>
<input asp-for="Add_No" class="form-control" id="t1" name="A" />
<span asp-validation-for="Add_No" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="getStudentInfo" class="btn btn-primary" id="btngetStudentInfo" />
</div>
}
</td>
<td>
<ul>
#if (ViewBag.students != null)
{
#foreach (var std in ViewBag.students)
{
<li>
#std
</li>
}
}
</ul>
</td>
</tr>
</table>
Code for Controller
public class PaymentsController : Controller
{
private readonly ConnectionString _context;
public PaymentsController(ConnectionString context)
{
_context = context;
}
public IActionResult Wcreate(Welfare welfare, string A)
{
int maxR_No = _context.Welfare.Max(p => p.R_No);
maxR_No = maxR_No + 1;
welfare.R_No = maxR_No;
if (ModelState.IsValid)
{
_context.Add(welfare);
_context.SaveChanges();
ModelState.Clear();
}
return View();
}
public ActionResult getStudentInfo(string A)
{
var items = _context.Students.Where(x => x.Add_No == A)
.Select(x => new
{
P1 = x.F_Name,
P2 = x.Class + "-" + x.ClassNo
});//.ToList();
ViewData["students"] = items;
return RedirectToAction("Wcreate");
}
namespace Student_Management.Models
{
public class Welfare
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int R_No { get; set; }
[Required]
public string Add_No { get; set; }
[Required]
public string Grade { get; set; }
[Required]
public string STClassNo { get; set; }
[Required]
public string Month { get; set; }
[Required]
public string Year { get; set; }
[Required]
public string Rs { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
public string cmt { get; set; }
As hint given by Jasen, I modified my action method and view as follows.
<td>
#using (Html.BeginForm("getStudentInfo", "Payments", FormMethod.Post))
{
<div class="form-group">
<label asp-for="Add_No" class="control-label"></label>
<input asp-for="Add_No" class="form-control" id="t1" name="A" />
<span asp-validation-for="Add_No" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="getStudentInfo" class="btn btn-primary" id="btngetStudentInfo" />
</div>
}
</td>
<p>#TempData["info"]</p>
<p>#(TempData["info2"] +"-" + TempData["info3"])</p>
Action method
public ActionResult getStudentInfo(string A)
{
var items = _context.Students.Where(x => x.Add_No == A)
.Select(x => new
{
P1 = x.F_Name,
P2 = x.Class,
p3=x.ClassNo
}).ToList();
TempData["info"] = items[0].P1;
TempData["info2"] = items[0].P2;
TempData["info3"] = items[0].p3;
return RedirectToAction("Wcreate");
}
I am trying to display a list of dynamic check boxes and allow the user to select one or more. Once returned to the controller, I would need to take the ids of all the checked ones and write a record for each to the database.
Below are the pieces of code that relate to this.
DTO
public class OfficeVisitPartOfBodyDisplay
{
public int PartOfBodyId { get; set; }
public string PartOfBodyName { get; set; }
public bool PartOfBodyChecked { get; set; }
}
Model
public class OfficeVisitModel
{
public OfficeVisitEntity OfficeVisit { get; set; }
public TList<PartOfBodyEntity> PartOfBodies { get; set; }
public TList<OfficeVisitPartOfBodyEntity> OfficeVisitPartOfBodies { get; set; }
public List<OfficeVisitPartOfBodyDisplay> OfficeVisitPartOfBodyDisplays { get; set; }
public string PatientName { get; set; }
}
View (The part in question)
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Pain Area(s):</legend>
<% foreach (OfficeVisitPartOfBodyDisplay officeVisitPartOfBodyDisplay in Model.OfficeVisitPartOfBodyDisplays)
{ %>
<label for="partofbodydisplay<%= officeVisitPartOfBodyDisplay.PartOfBodyId %>"><%= officeVisitPartOfBodyDisplay.PartOfBodyName%></label>
<input type="checkbox" id="partofbodydisplay<%= officeVisitPartOfBodyDisplay.PartOfBodyId%>" name="partofbodydisplay" value="<%= officeVisitPartOfBodyDisplay.PartOfBodyName%>" />
<% } %>
</fieldset>
</div>
Controller, the OfficeVisitPartOfBodyDisplays in the model and the partofbodydisplay always come back with no data.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ActivePainArea(OfficeVisitModel model, OfficeVisitPartOfBodyDisplay[] partofbodydisplay, string submitButton)
{
switch (submitButton)
{
case "Save":
model.Message = "Save Coming Soon";
return View(model);
case "Cancel":
model.Message = "Cancel Coming Soon";
return View(model);
case "Complaint":
return RedirectToAction("ActiveComplaint", new { patientId = model.OfficeVisit.PatientId, readOnly = false });
case "Patient History":
model.Message = "Patient History Coming Soon";
return View(model);
//return RedirectToAction("ActivePatientHistory", new { patientId = model.OfficeVisit.PatientId });
default:
return View(model);
}
}
give this a try:
Controller:
public ActionResult ActivePainArea(OfficeVisitModel officeVisitPartOfBodyDisplay, string submitButton) {
View:
<div data-role="fieldcontain">
<% using (Html.BeginForm()) { %>
<fieldset data-role="controlgroup">
<legend>Pain Area(s):</legend>
<% var i = 0; %>
<% foreach (var officeVisitPartOfBodyDisplay in Model.OfficeVisitPartOfBodyDisplays) { %>
<label for="partofbodydisplay<%= officeVisitPartOfBodyDisplay.PartOfBodyId %>">
<%= officeVisitPartOfBodyDisplay.PartOfBodyName%></label>
<%: Html.CheckBox("OfficeVisitPartOfBodyDisplays[" + i.ToString() + "].PartOfBodyChecked", officeVisitPartOfBodyDisplay.PartOfBodyChecked)%>
<% i++; %>
<% } %>
<input type="submit" value="save" />
</fieldset>
<% } %>
</div>
Also you might want to reference this page for more information:
Phil Haacked Model Binding To A List
How will I show the correct DsiplayName on my view considering the following model.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Project.Models.RegisterViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{%>
<table>
<tr>
<td class="label">
<%: Html.LabelFor(model => model.User.UserPrimaryEmail)%>
</td>
<td class="field">
<%: Html.TextBoxFor(model => model.User.UserPrimaryEmail)%>
</td>
<td class="field-error">
<div class="field-error-msg">
<%: Html.ValidationMessageFor(model => model.User.UserPrimaryEmail)%>
</div>
</td>
</tr>
</table>
</asp:Content>
public class RegisterViewModel
{
public User User { get; set; }
}
[MetadataType(typeof(UserMetaData))]
public partial class User : UserBase
{
//Inherits from Generated Class UserBase
//to set default values here for the constructor
// Not used except as a source of metadata
public class UserMetaData
{
[Required]
[DisplayName("Email Login")]
[DataType(DataType.EmailAddress)]
[Email(ErrorMessage = "Invalid Email")]
public string UserPrimaryEmail { get; set; }
}
}
The form does not display "Email Login" but "UserPrimaryEmail"
You View is strongly typed to Project.Models.RegisterViewModel, however you are adding your Data Annotations to the User Object.
Generally you would have:
public class RegisterViewModel
{
[Required]
[DisplayName("Email Login")]
[DataType(DataType.EmailAddress)]
[Email(ErrorMessage = "Invalid Email")]
public String Email { get; set; }
.....
other properties
}
How will I show the correct DsiplayName on my view considering the following model.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Project.Models.RegisterViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{%>
<table>
<tr>
<td class="label">
<%: Html.LabelFor(model => model.User.UserPrimaryEmail)%>
</td>
<td class="field">
<%: Html.TextBoxFor(model => model.User.UserPrimaryEmail)%>
</td>
<td class="field-error">
<div class="field-error-msg">
<%: Html.ValidationMessageFor(model => model.User.UserPrimaryEmail)%>
</div>
</td>
</tr>
</table>
</asp:Content>
public class RegisterViewModel
{
public User User { get; set; }
}
[MetadataType(typeof(UserMetaData))]
public partial class User : UserBase
{
//Inherits from Generated Class UserBase
//to set default values here for the constructor
// Not used except as a source of metadata
public class UserMetaData
{
[Required]
[DisplayName("Email Login")]
[DataType(DataType.EmailAddress)]
[Email(ErrorMessage = "Invalid Email")]
public string UserPrimaryEmail { get; set; }
}
}
The form does not display "Email Login" but "UserPrimaryEmail"
You View is strongly typed to Project.Models.RegisterViewModel, however you are adding your Data Annotations to the User Object.
Generally you would have:
public class RegisterViewModel
{
[Required]
[DisplayName("Email Login")]
[DataType(DataType.EmailAddress)]
[Email(ErrorMessage = "Invalid Email")]
public String Email { get; set; }
.....
other properties
}