ASP-routing from tavlerow instead of anchor - c#

I'm trying to learn asp.net and I'm trying to use the ASP routing directly from the tablerow (tr), instead of for each anchor point inside the cell.
Below code, I'm able to click the "Case ID" in my table, but this leaves some unclickable area around the actual text. I basically want to be able to simply select the row and pass the #sc.ID for a database query in the ViewCase-page.I want end-user to click "category" (and several columns in the future), without having to define tags everyhwere.
#foreach (var sc in Model.Cases)
{
<tr asp-area="" asp-page="ViewCase" asp-route-ID="#sc.ID">
<td>
<a asp-area="" asp-page="ViewCase" asp-route-ID="#sc.ID">
Case #Html.DisplayFor(Moldel => #sc.ID)
</a>
</td>
<td>
#Html.DisplayFor(Moldel => #sc.Category)
</td>
</tr>
}

It seems you do not want not want to specify the a tag every where. Tag helper does not work for table element, you just add js in the tr element like below:
<table class="table">
#foreach (var sc in Model.Cases)
{
<tr onclick="window.location.href='/ViewCase?ID=#sc.ID'">
<td>
Case #Html.DisplayFor(Moldel => #sc.ID)
</td>
<td>
#Html.DisplayFor(Moldel => #sc.Category)
</td>
</tr>
}
</table>

Related

How to update each row of a table dynamically in a Asp.Net Core

I'm developing a web application using Asp.Net Core(Razor Pages),and I have a table with three columns,one representing cellphone numbers,the other one text messages that are supposed to be sent to each one and the last one showing results.I'm looking for a way to update the last column of each row and have it highlighted as each messages is being sent to the cellphone number by clicking the Send To All button down the table.How can I accomplish it? Thanks for your responses in advance.
<div class="row mt-2">
<table class="table table-striped table-responsive-md">
<thead class="thead-dark">
<tr>
<th>
#Html.DisplayNameFor(model => model.MessageList[0].ReceiverCellPhone)
</th>
<th>
#Html.DisplayNameFor(model => model.MessageList[0].Text)
</th>
<th>
#Html.DisplayNameFor(model => model.MessageList[0].Result)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.MessageList)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ReceiverCellPhone)
</td>
<td>
#Html.DisplayFor(modelItem => item.Text)
</td>
<td>
#Html.DisplayFor(modelItem => item.Result)
</td>
<td></td>
</tr>
}
</tbody>
</table>
<button type=submit value=Send to All/>
</div>
I think in scenarios like this, we want to have our javascript as unobtrusive as possible by attaching events to actions through javascript rather than through the html attributes.
with that, you would probably want something like the following:
document.getElementById('ButtonId').addEventListener('click', function() {
// you are now in the button click context
// you can now either fire one asyncronous request which encapsulates all the
rows or you can iterate through the table rows and fire individual requests. The below shows the second example
var table = document.getElementById('TableId');
var url = "url to endpoint you want to call';
for (var i = 1; i < table.rows.length; i++) { // 1 so we miss the header
// get the relevant id of the request you want to send
var id = "whatever cell you need";
let request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (this.readyState === 4) {
//success so you can change the cell you want to change
} else {
document.body.className = 'error';
}
}
request.open("post", url, true);
request.send('this should be whatever you want to send to the request - id object maybe");
}
});
if you want to put the function as a proper function or variable then you can easily do that as well to make the code a little easier to read
I haven't used Razor syntax for a while but this is the idea:
An array of model comes to the view and your model needs to have an ID property.
When you're rendering the html use that ID to identify each row of your model, for example:
<tr id="#item.Id">
and each row can have its own trigger like this for example:
<button onClick="sendMessage(#item.Id)">
a JavaScript function can take that function sendMessage(id) and then you can query that row and update its UI. for example before sending the request you can create an loading element and using JavaScript promise, update that to a success or fail icon.
But if I'm understanding right you want to have a send all button. In that case you can just query third <td> of each row and update its UI:
document.querySelectorAll('td:nth-child(3)').forEach(e => {
//update UI
})
Hope this was helpful.

Retrieve the table data with xpath and Selenium

I have HTML with looks basically like the following
....
<div id="a">
<table class="a1">
<tbody>
<tr>
<td><a href="a11.html>a11</a>
</tr>
<tr>
<td><a href="a12.html>a12</a>
</tr>
</tbody>
<table>
</div>
...
The following coding in C# I used, however, I cannot retrieve the URL in this stage
IWebElement baseTable = driver.FindElement(By.ClassName(TableID));
// gets all table rows
ICollection<IWebElement> rows = baseTable.FindElements(By.TagName("tr"));
// for every row
IWebElement matchedRow = null;
foreach(var row in rows)
{
Console.Write (row.FindElements(By.XPath("td/a")));
}
First of all, you gave us invalid markup. Right one:
<div id="a">
<table class="a1">
<tbody>
<tr>
<td>
a11
</td>
</tr>
<tr>
<td>
a12
</td>
</tr>
</tbody>
</table>
</div>
If you have only one anchor in table row, you should use this code to retrieve url:
IWebElement baseTable = driver.FindElement(By.ClassName(TableID));
// gets all table rows
ICollection<IWebElement> rows = baseTable.FindElements(By.TagName("tr"));
// for every row
IWebElement matchedRow = null;
foreach (var row in rows)
{
Console.WriteLine(row.FindElement(By.XPath("td/a")).GetAttribute("href"));
}
You need to get href attribute of found element. Otherwise, row.FindElement(By.XPath("td/a") will print type name of the IWebElement inherited class, because it is an some type object, not string.
This does not look like a valid xpath to me
Console.Write (row.FindElements(By.XPath("td/a")));
try
Console.Write (row.FindElements(By.XPath("/td/a")));

create multi instance backward-timer jquery plugin in MVC razor?

i have page view list like
#foreach (var item in Model)
{
<tr>
<td class="colcode">
#Html.DisplayFor(modelItem => item.SMCode)
</td>
<td class="colname">
#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="colip">
#Html.DisplayFor(modelItem => item.IP)
</td>
<td class="coloffsetfund">
<div>
<span id="#item.IP.Replace(".","")"></span>
</div>
<div>
<span id="#item.SMCode"></span>
</div>
<script type="text/javascript">
$(document).ready(function () {
idtimer = '##item.IP.Replace(".","")';
password = '#item.Password';
ip = '#item.IP';
smcode = '#item.SMCode';
startTimer(idtimer);
$(idtimer).backward_timer({
seconds: '#item.DelaySecond',
on_exhausted: function (timer) {
alert('stop timer:' + idtimer);
//ajax call to update value
}
});
});
</script>
My list have 2 items but i dont know why. when event on_exhausted of timer excute, it always is the last item. i dont know what is logic here.How do I alert correct idtimer. thanks for your help!!!
sry guys,
i knew where is my problem, because i use variable to assign value, and when generated HTML, the variable always contain lastest value. i fixed it when use direct call like
$('##item.IP.Replace(".","")').backward_timer({
for other guy get problem same me :)
thank you.

Multiplying a textbox with a cell in a dynamically created table with JQuery

I have a dynamically created table with id called "editTable" that looks as follows:
<tbody>
#{var i = 0;}
#foreach (var item in Model)
{
<tr>
<td width="25%">
#Html.DisplayFor(modelItem => item.Product.Name)
</td>
<td width="25%">
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td width="25%">
<div class="editor-field">
#Html.EditorFor(modelItem => item.UnitPrice)
#Html.ValidationMessageFor(model => item.UnitPrice)
</div>
</td>
<td width="25%" id="total"></td>
</td>
</tr>
}
</tbody>
The 3th td-element consists of a C# textbox that is turned into a element in html.
Now I want to multiply the quantity by the unit price to display this value in the 4th td element next to it. This value should update every time the value in the textbox is adjusted. I am a newbie at JQuery / JavaScript and came up with the following code:
// Calculating quantity*unitprice
$('#editTable tr td:nth-child(3) input').each( function (event) {
var $quant = $('#editTable tr td:nth-child(2)', this).val();
var $unitPrice = $('#editTable tr td:nth-child(3) input', this).val();
$('#editTable tr td:nth-child(4)').text($quant * $unitPrice);
});
This doesn't work and only displays NaN in the 4th element. Can anyone help me updating this code to a working version? Any help would be very much appreciated.
I geussed you accidentally switched units and price because it has more logic to change the number of units then the price. I took your html and javascript and tried to change as little as possible to make it work (I'm not saying the solution is perfect, I just don't want to give you a totaly different example of how to do it).
The html (The C# is irrelevant for this problem):
<table id="editTable">
<tbody>
<tr>
<td width="25%">
Product name
</td>
<td width="25%">
5
</td>
<td width="25%">
<div class="editor-field">
<input id="UnitPrice" name="UnitPrice" type="number" value="2" style="width:40px" />
</div>
</td>
<td width="25%" id="total"></td>
</tr>
</tbody>
</table>
The javascript/jquery (which should run on load):
$('#editTable tr td:nth-child(3) input').each(updateTotal);
$('#editTable tr td:nth-child(3) input').change(updateTotal);
var element;
function updateTotal(element)
{
var quantity = $(this).closest('tr').find('td:nth-child(2)').text();
var price = $(this).closest('tr').find('td:nth-child(3) input').val();
$(this).closest('tr').find('td:nth-child(4)').text(quantity * price);
}
The problem you had were with jquery. I've created a function that recieves an element (in our case it's your UnitPrice input), then it grabs the closest ancestor of type tr (the row it's in) and from there it does what you've tried to do.
You've used jquery selector to get all 2nd cells in all table rows, the closest('tr').find limits it to the current row.
You've tried to use .val() on a td element, you should use either .text() or .html(). Instead, You can also add a data-val="<%=value%>" on the td and then use .data('val').
It will be better to take the units directly from $(element).val() and no going to the tr and then back into the td and the input.
To see it working: http://jsfiddle.net/Ynsgf/1/
I hope I didn't caused you any confusion with my explanation and the options I gave you.
Here is another way to write the jquery part.
$('#editTable tr').each(function (i, row) {
var $quant = $(row).find('.editor-field input').val();
var $unitPrice = $(row).find('.editor-field input').val();
$(row).find('td:nth-child(4)').text($quant * $unitPrice);
});

Finding the child of a parent's sibling element with WatiN

The scenario that I am looking at is that we have a table with multiple columns. One of those columns has a name, another has a dropdown list. I need to manipulate the dropdown for a row that contains a particular name. I looked at the source output, and tried getting the element's grandparent (the table row) so that I could search for the list. However, there was no such search functionality when I used the parent object.
It seems like there would be a lot of this kind of scenario in automating/testing a site, but I have not found anything after searching for a couple of hours. Any help would be appreciated.
EDIT: The application in question is an ASP.NET, and the output HTML is gnarly at best. However, here is a cleaned up example of what the HTML being searched looks like:
<table class="myGrid" cellspacing="0" cellpadding="3" rules="all" border="1" id="ctl00_content_MyRpt_ctl01_MyGrid" style="border-collapse:collapse;">
<tr align="left" style="color:Black;background-color:#DFDBDB;">
<th scope="col">Name</th><th scope="col">Unit</th><th scope="col">Status</th><th scope="col">Action</th>
</tr>
<tr>
<td>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_Name">JOHN DOE</span>
</td>
<td>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_UnitType">Region</span>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_UnitNum">1</span>
</td>
<td>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_Status">Complete</span>
</td>
<td class="dropdown">
<select name="ctl00$content$MyRpt$ctl01$MyGrid$ctl02$ActionDropDown" onchange="javascript:setTimeout('__doPostBack(\'ctl00$content$MyRpt$ctl01$MyGrid$ctl02$ActionDropDown\',\'\')', 0)" id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_ActionDropDown" class="dropdown">
<option value="123456">I want to...</option>
<option value="Details.aspx">View Details</option>
<option value="Summary.aspx">View Summary</option>
<option value="DirectReports.aspx">View Direct Reports</option>
</select>
</td>
</tr>
<tr>
...
</tr>
</table>
I found a way to do what I wanted. It is probably not the best or most elegant solution, but it works (it is not production code).
private void btnStart_Click(object sender, EventArgs e)
{
using (var browser = new IE("http://godev/review"))
{
browser.Link(Find.ByText("My Direct Reports")).Click();
TableRow tr = browser.Span(Find.ByText("JOHN DOE")).Parent.Parent as TableRow;
SelectList objSL = null;
if (tr.Exists)
{
foreach (var td in tr.TableCells)
{
objSL = td.ChildOfType<SelectList>(Find.Any) as SelectList;
if (objSL.Exists) break;
}
if (objSL != null && objSL.Exists)
{
Option o = objSL.Option(Find.ByText("View Direct Reports"));
if (o.Exists) o.Select();
}
}
}
}
Hopefully this saves someone a little time and effort. Also, I would love to see if someone has a better solution.

Categories

Resources