How to include a copy button in Razor pages - c#

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);
}

Related

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.

How to post data to razor page code behind asp.net core

I want to implement a bulk operation function, but I cannot post my data to the razor page code behind, anyone can help? Please check my code below
<form method="post" asp-page="./Index">
<div class="row">
<div class="col-md-12">
<table class="table table-hover table-bordered" style="margin-top:15px;">
<thead>
<tr class="info">
<th></th>
<th>
<a asp-page="./Index" asp-route-sortOrder="#Model.NumberSort">
#Html.DisplayNameFor(model => model.Products[0].Number)
</a>
</th>
<th>
#Html.DisplayNameFor(model => model.Products[0].Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Products)
{
<tr>
<td>
#Html.CheckBoxFor(modelItem => item.Checked)
</td>
<td class="success">
#Html.DisplayFor(modelItem => item.Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a asp-page="./Details" asp-route-id="#item.ID" class="btn btn-info">details</a>
<a asp-page="./Edit" asp-route-id="#item.ID" class="btn btn-warning">edit</a>
<a asp-page="./Delete" asp-route-id="#item.ID" class="btn btn-danger">delete</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-md-10">
#{
var items = Model.Products.Where(x => x.Checked);
}
<input type="submit" name="bulkUpload" value="bulk upload" asp-route-data="#items"/>
</div>
</div>
</form>
public async Task OnPostAsync(List<Product> upload)
{
}
You need to render your products in such way that the Modelbinder will be able to pick them up on form submit and pass them into the codebehind.
Something like this (done by hand so it might not compile at first):
#{
for (int i = 0; i < Model.Products.Count; i++)
{
<input type="checkbox" asp-for="Model.Produtcs[i].Checked" />
#Model.Products[i].Number
#Model.Products[i].Name
}
}
This will render HTML like
<input type="checkbox" name="Products[0].Checked" />
<input type="checkbox" name="Products[1].Checked" />
<input type="checkbox" name="Products[2].Checked" />
And it should get back to your OnPostAsync. If not then try changing
public async Task OnPostAsync(List<Product> upload)
to
public async Task OnPostAsync(YourModel model)
What ever your full model is named.
This is then redundant:
#{
var items = Model.Products.Where(x => x.Checked);
}

Loading Partial View within Tooltip

I would like to use tooltip within my index view so that I can display details for the items in my table on mouseover. The trick is that I would like to use a partial view within the tooptip popup window.
Index View
<script>
$(function () {
$('#theText').hover(function () {
$('#theDetails').show();
}, function () {
$('#theDetails').hide();
});
});
</script>
#{bool CanView = ViewBag.IsAdmin;}
#if (CanView == true)
{
<h2>Active Index - Software License (Full Viewer)</h2>
using (Html.BeginForm("Index", "SoftwareLicense", FormMethod.Get))
{
#Html.AntiForgeryToken()
<p>
<button onclick="location.href='#Url.Action("Create", "SoftwareLicense")';return false;">Create</button>
Search Keyword: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<button type="submit">Search</button>
<button onclick="location.href='#Url.Action("Deleted", "SoftwareLicense")';return false;">View Inactive Software</button>
</p>
}
<html>
<body>
<table class="table">
<tr>
<th>
#Html.ActionLink("Software Name", "Index", new { sortOrder = ViewBag.SoftNameSort, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("License Type", "Index", new { sortOrder = ViewBag.LicenseType, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("End Date", "Index", new { sortOrder = ViewBag.EndDateSort, currentFilter = ViewBag.CurrentFilter })
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td id="theText">
#Html.DisplayFor(modelItem => item.SoftwareName)
</td>
<td id="theDetails">#Html.Partial("_PopupDetails", (WBLA.Models.SoftwareLicense)item)</td>
<td>
#Html.DisplayFor(modelItem => item.LicenseType)
</td>
<td>
#Html.DisplayFor(modelItem => item.EndDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.SoftwareID }) |
#Html.ActionLink("Details", "Details", new { id = item.SoftwareID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.SoftwareID })
</td>
</tr>
}
</table>
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
</body>
</html>
Partial View
#model WBLA.Models.SoftwareLicense
<table>
<tr>
<th>
#Html.LabelFor(model => model.SoftwareName)
</th>
<td>
#Html.DisplayFor(model => model.SoftwareName)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.SoftwareKey)
</th>
<td>
#Html.DisplayFor(model => model.SoftwareKey)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.Price)
</th>
<td>
#Html.DisplayFor(model => model.Price)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.DepartmentName)
</th>
<td>
#Html.DisplayFor(model => model.DepartmentName)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.LicenseFilePath)
</th>
<td>
#Html.DisplayFor(model => model.LicenseFilePath)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.LicenseType)
</th>
<td>
#Html.DisplayFor(model => model.LicenseType)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.StartDate)
</th>
<td>
#Html.DisplayFor(model => model.StartDate)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.EndDate)
</th>
<td>
#Html.DisplayFor(model => model.EndDate)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.NotifyTime)
</th>
<td>
#Html.DisplayFor(model => model.NotifyTime)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.Email)
</th>
<td>
#Html.DisplayFor(model => model.Email)
</td>
</tr>
</table>
Results in Browser
http://i.stack.imgur.com/yNQ0T.png
When I hover over "test1" the tooltip responds as I would like (it expands and shows details like "test10" is displayed), however, the rest of the entries do not respond or collapse on mouseover and mouseoff.
You should change your <td> elements to use the class attributes to identify them.
<td class="theText">
#Html.DisplayFor(modelItem => item.SoftwareName)
</td>
<td class="theDetails">#Html.Partial("_PopupDetails", (WBLA.Models.SoftwareLicense)item)</td>
then change your script to work with the class names.
$(function () {
$('.theText').hover(function () {
$(this).parent().find('.theDetails').show();
}, function () {
$(this).parent().find('.theDetails').hide();
});
});

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

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>

Categories