C# MVC4 table with multiple submit buttons - always sends the same data - c#

I have a table inside my view that lists case details in each row. Every row has a submit button called "View Details". I have two hidden fields, TicketNumber and CaseId that are submitted when the user clicks the "View Details" button.
The problem is: it always sends the TicketNumber and CaseId of the first case in the table no matter which "View Details" button is pressed.
Here is the code of the view:
#model IEnumerable<Models.Case>
#{
ViewBag.Title = "AbandonedVehiclesLandingPage";
}
<h2>AbandonedVehiclesLandingPage</h2>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.TicketNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Status)
</th>
<th>
#Html.DisplayNameFor(model => model.SubmittedOn)
</th>
<th></th>
</tr>
</table>
#using (Html.BeginForm("ViewCase", "Home",FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TicketNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.SubmittedOn)
</td>
<td>
<input type="hidden" value="#item.TicketNumber" name="TicketNumber" />
<input type="hidden" value="#item.CaseId" name="CaseId" />
<input type="submit" value="View Details" />
</td>
</tr>
}
</table>
}
Here is the receiving Action:
[HttpPost]
public ActionResult ViewCase(string TicketNumber, string CaseId)
{
string token = (string)Session["token"];
if(token!=null)
{
if (provider.ValidateUser(Session["token"].ToString(), ""))
{
CaseService service = new CaseService("");
CaseNote caseInfo = service.fetchSingleCase(TicketNumber, CaseId);
return View("ViewCase", caseInfo);
}
}
return Redirect(HttpContext.Application["connectUrl"].ToString()
+ HttpContext.Application["redirectUrl"].ToString());
}
Last thing to say, it worked up until the point I lost the original View code and had to re-write it again. It feels like something small I am missing here.

Change your table as follows:
<table>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TicketNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.SubmittedOn)
</td>
<td>
#using (Html.BeginForm("ViewCase", "Home",FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="hidden" value="#item.TicketNumber" name="TicketNumber" />
<input type="hidden" value="#item.CaseId" name="CaseId" />
<input type="submit" value="View Details" />
}
</td>
</tr>
}
</table>

Related

How to include a copy button in Razor pages

I'm new to .Net Razor pages and followed this tutorial by FreeCodeCamp
I made an Index page with the help of the tutorial and wanted to add a copy button beside the entries but can't find a way to do so, here is the image of how the table looks, and here is the code:
//Index.cshtml.cs
private readonly ApplicationDbContext _db;
public IndexModel(ApplicationDbContext db)
{
_db = db;
}
public IEnumerable<PasswordEntry> PasswordEntries { get; set; }
public async Task OnGet()
{
PasswordEntries = await _db.PasswordEntry.ToListAsync();
}
//Index.cshtml
<br />
<div class="container row p-0 m-0">
<div class="col-9">
<h4>Passwords</h4>
</div>
</div>
<div class="col-12 border p-3 mt-3">
<form method="post">
#if (Model.PasswordEntries.Count() > 0)
{
<table class="table table-striped border">
<tr class="table-secondary">
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Name"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Url"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Email"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Username"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Password"></label>
</th>
<th>
</th>
</tr>
#foreach (var item in Model.PasswordEntries)
{
<tr>
<td>
#Html.DisplayFor(m => item.Name)
</td>
<td>
#Html.DisplayFor(m => item.Url)
</td>
<td>
#Html.DisplayFor(m => item.Email)
</td>
<td>
#Html.DisplayFor(m => item.Username)
</td>
<td>
#Html.TextBoxFor(m => item.Password, new { type = "password", disabled = "disabled" })
</td>
<td>
<button asp-page-handler="Delete" asp-route-id="#item.Id">Delete</button>
<a asp-page="Edit" asp-route-id="#item.Id">Edit</a>
</td>
</tr>
}
</table>
}
else
{
<h1>no entries available</h1>
}
</form>
</div>
I did try adding a copy button beside the delete and edit buttons with onClick function, on click it would call a funcition in #section Script area, but it didn't work probably cause the foreach loop ends after displaying the result,
what would be a good way to implement the copy button?
If you want to copy the line when click Copy button,here is a demo:
<div class="col-12 border p-3 mt-3">
<form method="post">
#if (Model.PasswordEntries.Count() > 0)
{
<table class="table table-striped border">
<tr class="table-secondary">
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Name"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Url"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Email"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Username"></label>
</th>
<th>
<label asp-for="PasswordEntries.FirstOrDefault().Password"></label>
</th>
<th>
</th>
</tr>
#foreach (var item in Model.PasswordEntries)
{
<tr>
<td>
#Html.DisplayFor(m => item.Name)
</td>
<td>
#Html.DisplayFor(m => item.Url)
</td>
<td>
#Html.DisplayFor(m => item.Email)
</td>
<td>
#Html.DisplayFor(m => item.Username)
</td>
<td>
#Html.TextBoxFor(m => item.Password, new { type = "password", disabled = "disabled" })
</td>
<td>
<button asp-page-handler="Delete" asp-route-id="#item.Id">Delete</button>
<button onclick="copy(this)">Copy</button>
<a asp-page="Edit" asp-route-id="#item.Id">Edit</a>
</td>
</tr>
}
</table>
}
else
{
<h1>no entries available</h1>
}
</form>
</div>
js:
#section Scripts{
<script>
function copy(t) {
$("table")[0].innerHTML += $(t).parent().parent()[0].outerHTML;
}
</script>
}
result:
Update:
If you want to copy password to clipboard.Try to use the folowing js function:
function copy(t) {
var password = $(t).parent().parent()[0].children[4].children[0].value;
navigator.clipboard.writeText(password);
}

Action based redirect ASP.Net Core Razor

Synopsis of the place I am at:
In my program on page 1 they select a printer and click a button which submits a service call and loads the next page, machine information. The redirect action calls the following method:
public async Task<IActionResult> OnGetSelectThisPrinter(int? printerID)
{
var printerServiceCall = new Service_Calls
{
PrinterID = (int)printerID,
Time = DateTime.Now,
Date = DateTime.Now
};
_context.Service_Calls.Add(printerServiceCall);
await _context.SaveChangesAsync();
var ServiceCalls = from m in _context.Service_Calls
select m;
Service_Calls ServiceCall = ServiceCalls.Last();
return RedirectToPage("MachineInformaion?id=" + ServiceCall.ID);
//return RedirectToPage("./Index");
}
In this code the printerID = 1 is a placeholder until I work out how to pass in a specific machines details (any help on passing through that would be helpful).
The HTML for this page, with the buttons, is as follows:
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Printer[0].MachineID)
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.LogSortParam">#Html.DisplayNameFor(model => model.Printer[0].Log_ID)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.LeaseSortParam">#Html.DisplayNameFor(model => model.Printer[0].Lease_ID)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.SerialSortParam">#Html.DisplayNameFor(model => model.Printer[0].Serial_Number)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.SolutionSortParam">#Html.DisplayNameFor(model => model.Printer[0].Solution)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.AdditionalSortParam">#Html.DisplayNameFor(model => model.Printer[0].Additional_Info)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.InstallationSortParam">#Html.DisplayNameFor(model => model.Printer[0].InstallationDate)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.MonoClickSortParam">#Html.DisplayNameFor(model => model.Printer[0].Mono_Click)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.ColourCLickSortParam">#Html.DisplayNameFor(model => model.Printer[0].Colour_Click)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.MinimumSortParam">#Html.DisplayNameFor(model => model.Printer[0].Minimum)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.PartsSortParam">#Html.DisplayNameFor(model => model.Printer[0].Parts_Warranty)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.ITSortParam">#Html.DisplayNameFor(model => model.Printer[0].IT_Support)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.ContractSortParam">#Html.DisplayNameFor(model => model.Printer[0].Contract_Type)</a>
</th>
<th>Select Printer</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Printer) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.MachineID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Log_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Lease_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Serial_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Solution)
</td>
<td>
#Html.DisplayFor(modelItem => item.Additional_Info)
</td>
<td>
#Html.DisplayFor(modelItem => item.InstallationDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mono_Click)
</td>
<td>
#Html.DisplayFor(modelItem => item.Colour_Click)
</td>
<td>
#Html.DisplayFor(modelItem => item.Minimum)
</td>
<td>
#Html.DisplayFor(modelItem => item.Parts_Warranty)
</td>
<td>
#Html.DisplayFor(modelItem => item.IT_Support)
</td>
<td>
#Html.DisplayFor(modelItem => item.Contract_Type)
</td>
<td>
<form method="get" asp-page-handler="OnGetSelectThisPrinter" asp-route-id="#item.MachineID">
<button value="Select Printer" />
</form>
</td>
</tr>
}
</tbody>
</table>
However, at the moment the buttons don't do anything. It looks like they aren't going into the OnGetSelectThisPrinter Method. Any help would be greatly appreciated.
I suggest you can use <a> tag to access the handler, since you only need to pass a parameter.
<a asp-page="/Printer" asp-page-handler="SelectThisPrinter" asp-route-printerID="#item.MachineID">SelectThisPrinter</a>
Handler in Printer page:
public IActionResult OnGetSelectThisPrinter(int printerID)
{
...
}
To start, this tutorial gives a much more in depth discussion of the answer I'm about to give. Check it out: https://www.learnrazorpages.com/razor-pages/handler-methods
Hi there! Let's start with making the button work. In order to redirect the user to a particular action of the page, we can use the asp-page-handler attribute to specify the method that handles the request. Additionally, we use the asp-route-id attribute to describe which printer we have selected. Finally, we wrap this all up in a form. So, we replace
<input type="button" onclick="SelectThisPrinter()" value="Select Printer" />
with
<form method="get" asp-page-handler="selectThisPrinter" asp-route-id="#item.MachineID">
<button value="Select Printer" />
</form>
Then, in your code-behind, we can perform some simple changes to your handler. We change
public async Task<IActionResult> SelectThisPrinter()
{
int printerID = 1;
...
}
to
public async Task<IActionResult> OnGetSelectThisPrinter(int? printerId)
{
...
}
I hope this helps. Let me know if you have any further questions.

How to store an html element ID as a local variable in razor pages when html element is clicked

So I have a list of countries that I currently have displayed on the view.
#model IEnumerable<CountryViewer.Models.CountryModel>
#{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
#*<p>
<a asp-action="Create">Create New</a>
</p>*#
<div class="container-fluid">
<div class="row">
<div class="col">
<div class="form-group">
<label for="exampleFormControlSelect1">Example select</label>
<select class="form-control" id="exampleFormControlSelect1">
#foreach (var item in Model)
{
<option id="#item.Alpha3Code" >
#Html.DisplayFor(modelItem => item.Name)
</option>
}
</select>
<button type="submit" class="btn btn-primary" value="selectID">Submit</button>
</div>
</div>
<div class="col">
<div class="form-horizontal">
<hr />
<div class="form-group">
<table class="table table-responsive" style="width:400px">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Alpha3Code)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Population)
</th>
<th>
#Html.DisplayNameFor(model => model.Flag)
</th>
<th>
#Html.DisplayNameFor(model => model.Capital)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(model => item.Alpha3Code)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Population)
</td>
<td>
#Html.DisplayFor(modelItem => item.Flag)
</td>
<td>
#Html.DisplayFor(modelItem => item.Capital)
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
When a user selects one of the countries on the list I want to display that information. The way I thought to do it was to store the ID of the clicked element and then run a foreach loop to filter through and then display the information.
<tbody>
#foreach (var item in Model)
{
if (item.Alpha3Code == idselected)
{
<tr>
<td>
#Html.DisplayFor(model => item.Alpha3Code)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Population)
</td>
<td>
#Html.DisplayFor(modelItem => item.Flag)
</td>
<td>
#Html.DisplayFor(modelItem => item.Capital)
</td>
</tr>
}
}
</tbody>
How do I do this? or is there another simpler way? I have heard of using ajax but I am at a loss at how to begin. Any other suggestions?
The simplest way is when selecting an item in your select, do a redirect (ex: http://localhost:1234/yourpage/{{selectedId}} or http://localhost:1234/yourpage&selectedId={{...}}). Then use it to show selected data.
Another better solution, do an ajax request back to your API, and receive a JSON data, then bind those data using JavaScript.
If your list of items is small/light weight, you can even render all items and keep data in a hidden input or a js variable. Then on selecting an item in your select, just filter the data to display selected item.

MVC 5 ASP.NET IEnumerable<Item> does not contain a definition for "Inspection" and no extension method "inspection" accepting a first argument of type

I am trying to display certain data from my Inspections model in my Items Index view. They currently have a M:M relationship.
This is the error
Error CS1061 'IEnumerable<Item>' does not contain a definition for 'Inspection' and no extension method 'Inspection' accepting a first argument of type 'IEnumerable<Item>' could be found (are you missing a using directive or an assembly reference?)
Any advice? Thank you
This is Items Index
#model IEnumerable<NCSafety.Models.Item>
<table class="table">
<tr>
<th>
Hazard Picture
</th>
<th>
#Html.DisplayNameFor(model => model.Hazard.hazName)
</th>
<th>
#Html.DisplayNameFor(model => model.Inspection.ID)
</th>
<th>
#Html.DisplayNameFor(model => model.itemCorrActionDue)
</th>
<th>
#Html.DisplayNameFor(model => model.itemCorrActionCompleted)
</th>
<th>
#Html.DisplayNameFor(model => model.itemComment)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#{
if (item.imageContent != null &&
item.imageMimeType.Contains("image"))
{
string imageBase64 =
Convert.ToBase64String(item.imageContent);
string imageSrc = string.Format("data:" +
item.imageMimeType + ";base64,{0}", imageBase64);
<img src="#imageSrc" style="max-height:100px; max-
width:120px" class="img-responsive img-rounded" />
}
}
</td>
<td>
#Html.DisplayFor(modelItem => item.Hazard.hazName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Inspection.ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.itemCorrActionDue)
</td>
<td>
#Html.DisplayFor(modelItem => item.itemCorrActionCompleted)
</td>
<td>
#Html.DisplayFor(modelItem => item.itemComment)
</td>
<td>
<a href="/Items/Edit/#item.ID"><div class="glyphicon
glyphicon-pencil" style="margin-right:30px"></div></a>
<a href="/Items/Details/#item.ID"><div class="glyphicon
glyphicon-eye-open" style="margin-right:30px"></div></a>
<a href="/Items/Delete/#item.ID"><div class="glyphicon
glyphicon-remove"></div></a>
</td>
</tr>
}
</table>
<table>
#foreach (var item in Model.Inspection)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.SchoolID)
</td>
<td>
#Html.DisplayFor(modelItem => item.inspDate)
</td>
</tr>
}
</table>
if (Model.Count() == 0)
{
<h3>No Records Found.</h3>
<br />
Add Item
}
}
Download PDF
If this is your model:
IEnumerable<NCSafety.Models.Item>
Then none of these will work:
#Html.DisplayNameFor(model => model.Hazard.hazName)
Because IEnumerable<T> doesn't have any of those properties. Perhaps you meant to drill into an element of the IEnumerable<T> for the properties? Something like this:
#Html.DisplayNameFor(model => model.First().Hazard.hazName)
(repeat for your other properties)
Either Inspection is in the Model object or on the collection object that makes up the Model. It probably isn't on both.

Populate ArrayList based on checkbox

I'm trying to find a way to send an email to selected recipients based on whether or not their email has been checked. We have a database with the emails in, and I've manually added a checkbox to resultant table. On clicking "Send", I want the email to send to those people based on whether or not they've been checked.
I thought the best way to do this would be to create an ArrayList, and then use message.CC.Add(emailArray), but that gives invalid arguments.
I then tried
string Email = emailArray.ToString()
//and then
message.CC.Add(email)
which didn't give errors, but it only sends to whomever clicks the button, IE myself or another colleague, and doesn't add the CCs. SMTP etc is all correct, as the email will send, just not to the ticked recipients.
ArrayList emailArray = new ArrayList();
if (Request.Form["chkBox"].Equals(true))
{
emailArray.Add(db.tblMailRecipients.Include(t => t.Email));
}
string email = emailArray.ToString();
message.To.Add(email);
smtp.Send(message);
Response.Redirect("~/Home/Index");
The above code shows where I'm trying to get the emails and put it into the Arraylist.
Is it to do with how I'm getting the checkbox value and then relating (or not?) that to the row in the table?
We're using ASP.NET MVC with C#.
Any help would be appreciated :).
Thanks
Update
The following code is for the page listing recipients with the checkboxes:
#using (Html.BeginForm("SendEmail", "BulkMail", FormMethod.Post))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.Company)
</th>
<th>
#Html.DisplayNameFor(model => model.LastEmailDate)
</th>
<th>
Check
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Company)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastEmailDate)
</td>
<td>
<input id="chkBox" name="chkBox" type="checkbox" />
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.MailRecipientId }) |
#Html.ActionLink("Details", "Details", new { id=item.MailRecipientId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.MailRecipientId })
</td>
</tr>
}
</table>
<input type="submit" value="Submit" />
}
The message is hardcoded in the send mail function at the moment.
You have:
<input id="chkBox" name="chkBox" type="checkbox" />
Inside a foreach loop, which will repeat the id="chkBox", generating invalid HTML.
What you should do is create a Property in your Model. e.g.
public bool isChecked {get;set;}
Then display your Model using forloop: MVC Model binder requires the fields to be in the form: [0].PropertyName
#for(var i =0; i < Model.Count(); i++) {
<tr>
<td>
#Html.DisplayFor(m => m[i].LastName)
</td>
...... Removed HTML
<td>
#Html.CheckBoxFor(m => m[i].isChecked)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=Model[i].MailRecipientId }) |
..... Removed HTML
</td>
</tr>
}
When you Submit the Form:
[HttpPost]
public ActionResult SendEmail(List<CLASS_NAME> model)
{
var emails = model.Where(s => s.isChecked).Select(s => s.Email).ToArray();
............/////
}
Apologies for the lack of interaction with this thread, had other stuff come up which was urgently needed. Firstly, thanks for all your help. I had a look today and came up with the following solution:
Add
<input type="checkbox" name="chkBox" value="#item.Email" />
into the view where emails etc can be selected. I then added:
message.Bcc.Add(Request.Form["chkBox"])
To the controller for the SMTP etc, and it seems to work pretty well :).
Thanks

Categories