How to click on inneHTML String with Selenium? - selenium

I am iterating throw a table getting the rows:
<div class="table-responsive">
<table class="table table-striped" id="noteTable">
<thead>
<tr>
<th style="width: 20%" scope="col"></th>
<th style="width: 20%" scope="col">Title</th>
<th style="width: 60%" scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr id="notes" th:each="note : ${notes}">
<td>
<a class="btn btn-success" id="btn-edit-note"
th:onclick="showNoteModal([[${note.id}]],
[[${note.noteTitle}]], [[${note.noteDescription}]])">Edit</a>
<a th:href="#{|/home/delete-note/?title=${note.noteTitle}|}"
id="btn-delete-note" class="btn btn-danger">Delete</a>
</td>
<th scope="row" th:text="${note.noteTitle}"></th>
<td th:text="${note.noteDescription}"></td>
</tr>
</tbody>
</table>
</div>
With this code written below :
public void deleteNote(String title, String description) {
WebDriverWait wait = new WebDriverWait(driver, 2);
WebElement btnDeleteNote;
js.executeScript("arguments[0].click();", tabNotes);
WebElement homeWait = wait.until(webDriver ->
webDriver.findElement(By.id("btn-delete-note")));
for (WebElement note : notes) {
String noteTitle = note.getAttribute("innerHTML");
System.out.println(noteTitle);
if (noteTitle.contains(title)) {
js.executeScript("DELETE NOTE HERE);
}
}
}
When I get the row innerHTML I receive this result as String :
<td>
<a class="btn btn-success" id="btn-edit-note" onclick="showNoteModal(1,
"Note Title Test", "Note Description Test")">Edit</a>
Delete
</td>
<th scope="row">Note Title Test</th>
<td>Note Description Test</td>
- My question is: Thinking that the lines of a Table are Dynamic, how can I click on "< a >" tag element in the string row?

The element has to be unique because it has an id so you can just target it like this:
element = driver.find_element_by_id("btn-delete-note")
print(element.text)

Related

ASP.NET Core - How would I set a name with ID of HTML element on CSHTML

How would I set a name with ID of HTML element on CSHTML?
<tr>
<td>
#item.Items.ItemID
</td>
<td>
#item.Items.ItemModelDescription
</td>
<td class="text-right">
<input id="#item.Items.ItemID + 'UnitPrice'" class="form-control text-right" value="#item.Items.ItemUnitPrice" />
</td>
<td class="text-right">
<input id="#item.Items.ItemID + 'Quantity'" class="form-control text-right" value="#item.Quantity" oninput="return change_quantity('#item.Items.ItemID')"/>
</td>
<td class="text-right">
#(item.Quantity * item.Items.ItemUnitPrice)
</td>
<td>
<a class="btn btn-sm btn-danger btn-rounded" asp-controller="purchaseorderheader" asp-action="Remove" asp-route-id="#item.Items.ItemID"><span class="fa fa-trash"></span></a>
</td>
</tr>
I can't get the value of HTML element using javascript is there anyway or proper way of setting an id of each quantity input? Or any keywords to search regarding this one.
According to your code and description, I assume you want to calculate the cost based on the Quantity and the ItemUnitPrice. If that is the case, please refer to the following sample code, you can refer it to change your code:
ViewModel:
public class ItemViewModel
{
public int ItemId { get; set; }
public string ItemDescription { get; set; }
public decimal ItemUnitPrice { get; set; }
public decimalc Quantity { get; set; }
}
Index.cshtml: we could set the id attribute like this id='Quantity_#item.ItemId', after rendering, the output like Quantity_XXX:
#model IEnumerable<WebApplication6.Models.ItemViewModel>
<table class="table">
<thead>
<tr>
...
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#item.ItemId
</td>
<td>
#item.ItemDescription
</td>
<td class="text-right">
<input id="ItemUnitPrice_#item.ItemId" class="form-control text-right" type="text" value="#item.ItemUnitPrice" />
</td>
<td class="text-right">
<input id='Quantity_#item.ItemId' class="form-control text-right txtquantity" type="text" value="#item.Quantity" oninput="return change_quantity(this,#item.ItemId)" />
</td>
<td class="text-right">
#(item.Quantity * item.ItemUnitPrice)
</td>
<td>
<a class="btn btn-sm btn-danger btn-rounded" asp-controller="purchaseorderheader" asp-action="Remove" asp-route-id="#item.ItemId"><span class="fa fa-trash"></span></a>
</td>
</tr>
}
</tbody>
</table>
Then at the end of the Index.cshtml page, add the following JavaScript: we could use the parent() and closest() method to find the current row, and then find the relates elements in this row.
#section Scripts{
<script>
function change_quantity(e, itemid) {
//find the item unit price.
var price = $("#" + "ItemUnitPrice_" + itemid).val();
//find the quantity value.
var quantity = $("#" + "Quantity_" + itemid).val();
//calculate the cost and change the html content.
$(e).parent().closest("tr").find(".text-right:last").html((price * quantity).toFixed(2).toString());
}
</script>
}
The output like this:
you can use this approach
#foreach (var item in Model)
{
<tr id="tr-#item.ItemId">
<td>
#item.ItemId
</td>
<td>
#item.ItemDescription
</td>
<td class="text-right">
<input id="ItemUnitPrice_#item.ItemId" class="form-control text-right" type="text" value="#item.ItemUnitPrice" />
</td>
<td class="text-right">
<input id='Quantity_#item.ItemId' class="form-control text-right txtquantity" type="text" value="#item.Quantity" oninput="return change_quantity(this,#item.ItemId)" />
</td>
<td class="text-right">
#(item.Quantity * item.ItemUnitPrice)
</td>
<td>
<a class="btn btn-sm btn-danger btn-rounded" asp-controller="purchaseorderheader" asp-action="Remove" asp-route-id="#item.ItemId"><span class="fa fa-trash"></span></a>
</td>
</tr>
}

asp-validation-for not working under foreach due to same name issue

I am using asp-validation-for under foreach and facing following issues. suppose 3 text controls generated with foreach. I am using the [required] model annotation. "objGenExaminationTemplateChoicesModel" object is of ICollection in main model.
if first text controls is empty system is showing error message with
all 3 text controls.
if second or third is empty system is not
showing any message but don't proceed to post page due to model
error.
<table id="dtChoices" class="table table-borderless table-striped">
<thead class="bg-primary">
<tr>
<th class="text-left"><label asp-for="#Model.objGenExaminationTemplateChoicesModel.FirstOrDefault().ChoiseDescription" class="control-label"></label></th>
<th style="width:30px"><span class="sidenav-icon icon icon-plus-square pull-right" style="font-size:large"> </span></th>
</tr>
</thead>
<tbody>
#foreach (var objGenExaminationTemplateChoiceModel in Model.objGenExaminationTemplateChoicesModel)
{
iCounter = iCounter + 1;
<tr>
<td class="text-left form-group form-group-sm">
<input type="text" asp-for="#objGenExaminationTemplateChoiceModel.ChoiseDescription" class="form-control">
<span asp-validation-for="#objGenExaminationTemplateChoiceModel.ChoiseDescription" class="text-danger"></span>
</td>
<td>
<a href="#" class="text-warning btnDeleteRow" data-toggle="modal" data-target="#deleteConfirmationModalAlert">
<span class="sidenav-icon icon icon-trash pull-right" style="font-size:large"> </span>
</a>
</td>
</tr>
}
</tbody>
The objGenExaminationTemplateChoicesModel is a list model,so the model binding system would find the name by [i].propertyName.Change your code like below:
#model TestVmodel
<form>
<table id="dtChoices" class="table table-borderless table-striped">
<thead class="bg-primary">
<tr>
<th class="text-left"><label asp-for="#Model.objGenExaminationTemplateChoicesModel.FirstOrDefault().ChoiseDescription" class="control-label"></label></th>
<th style="width:30px"><span class="sidenav-icon icon icon-plus-square pull-right" style="font-size:large"> </span></th>
</tr>
</thead>
<tbody>
#{ var iCounter = 0;}
#for (int i = 0; i < Model.objGenExaminationTemplateChoicesModel.Count(); i++)
{
iCounter = iCounter + 1;
<tr>
<td class="text-left form-group form-group-sm">
<input type="text" asp-for="#Model.objGenExaminationTemplateChoicesModel[i].ChoiseDescription" class="form-control">
<span asp-validation-for="#Model.objGenExaminationTemplateChoicesModel[i].ChoiseDescription" class="text-danger"></span>
</td>
<td>
<a href="#" class="text-warning btnDeleteRow" data-toggle="modal" data-target="#deleteConfirmationModalAlert">
<span class="sidenav-icon icon icon-trash pull-right" style="font-size:large"> </span>
</a>
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="aa" />
</form>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
My testing model:
public class TestVmodel
{
public List<ObjGenExaminationTemplateChoicesModel> objGenExaminationTemplateChoicesModel { get; set; }
}
public class ObjGenExaminationTemplateChoicesModel
{
[Required]
public string ChoiseDescription { get; set; }
}
Result:

Post form data to controller

I want to submit the table row values of the rows that are checked to my controller. My controller is always receiving a parameter of value null.
#model IEnumerable<GoogleMapsAPIWeb.Models.Schedule>
#using (Html.BeginForm("Route", "Home", FormMethod.Post))
{
<div>
<table id="schedulerTable">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" >View</th>
<th scope="col">Site Id</th>
</tr>
</thead>
<tbody>
#foreach (var row in Model)
{
<tr>
<td>#Html.CheckBoxFor(c=>row.isSelected)</td>
<td class="smallerDataField">
<a>View</a>#*TODO add code to view*#
</td>
<td><div class="smallerDataField">#row.SiteId</div></td>
</tr>
}
</tbody>
</table>
<input id="btnFindRoute" type="submit" value="Plan Route" />
</div>
}
[HttpPost]
public ActionResult Route(IEnumerable<Schedule> Schedules)
{
Use for loop for this purpose. More info
for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>#Html.CheckBoxFor(c=> Model[i].isSelected)</td>
</tr>
...
}

How to change MVC Web Grid structure?

I am trying to show list of items in a MVC 4 Web Grid control. But I am unable to re-format my web grid as table structure below.
Web Grid structure like this.
Table structure like this.
Here is my razor code for web grid.
#{
var grid = new WebGrid(Model.EnrollPlanPriceLevelList, canPage: true, rowsPerPage: 10, selectionFieldName: "id", ajaxUpdateContainerId: "gridContent");
grid.Pager(WebGridPagerModes.NextPrevious);
if (grid.HasSelection)
{
var EnrollPlanPriceLevelID = grid.Rows[grid.SelectedIndex].Value;
}
}
#grid.GetHtml(
tableStyle: "table table-condensed table-striped table-hover no-margin",
headerStyle: "",
mode: WebGridPagerModes.All,
columns:
grid.Columns(
grid.Column("", format: (item) => item.GetSelectLink(item.EnrollPlanPriceLevelID.ToString())),
grid.Column("SchoolYears.Name", "School Year"),
grid.Column("EnrollPlans.PlanName", "Enroll Plan"),
grid.Column("PriceLevels.Name", "Price Level"),
grid.Column("Price", "Price"),
grid.Column("", format: #<text>#Html.Label("Edit", new { #id = item.EnrollPlanPriceLevelID, #class = "badge", #onclick = "bindplanprogram(" + item.EnrollPlanPriceLevelID + ")" }) </text>),
grid.Column("", format: #<text>#Html.ActionLink("Delete", "Delete", new { id = item.EnrollPlanPriceLevelID }, new { #class = "badge" }) </text>)
))
Here is the table structure
<table class="table table-condensed table-striped table-hover no-margin">
<thead>
<tr>
<th>School Year
</th>
<th>Enroll Plan</th>
<th>
<span class="span3">Early Bird</span>
<span class="span3">Value Pricing</span>
<span class="span4">Standard Pricing</span>
</th>
<th>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>2011-2012</td>
<td>A(k-8) Grade</td>
<td>
<span class="span3">$ 50</span>
<span class="span3">$ 60</span>
<span class="span3">$ 70</span>
</td>
<td>
<a class="badge">Edit</a>
<a class="badge">Delete</a>
</td>
</tr>
<tr>
<td>2011-2012</td>
<td>B (9-12)Grade</td>
<td>
<span class="span3">$ 70</span>
<span class="span3">$ 80</span>
<span class="span3">$ 90</span>
</td>
<td>
<a class="badge">Edit</a>
<a class="badge">Delete</a>
</td>
</tr>
<tr>
<td>2011-2012</td>
<td>Adult Ed. (age 18+)</td>
<td>
<span class="span3">$ 1500</span>
<span class="span3">$ 175</span>
<span class="span3">$ 200</span>
</td>
<td>
<a class="badge">Edit</a>
<a class="badge">Delete</a>
</td>
</tr>
</tbody>
</table>
I want to reformate my web grid structure as above table structure. Please tell me someone! How to change web grid structure accordingly?
The only way to achieve what you want with the WebGrid is to change the shape of the data you are passing in. Whether you do that in your SQL or whether you do that using LINQ to create a collection of anonymous types that have the appropriate properties is up to you, but the end result must be a collection of items that have public properties that match what you want as column names.

Element is not visible

I'm trying to parse and manipulate some data via Selenium and java (using Firefox as a browser and Ubuntu as an os).
The HTML code:
...
<div id="someName1">
<div id="someName2">
<div id="someName3">
<a class="sendMessegeLink" onclick="open_win(...)" title="someText1">
<img style="padding-left:5px; vertical-align:middle" src="..."/>
someText1
</a>
</div>
<table class="areaTable">
<tbody>
<tr>
<tr>
<tr class="someName4">
<td colspan="4">
<div id="SomeUniqueId" class="someName5" style="display: block;">
<table class="someName6">
<tbody>
<tr>
<tr>
<td colspan="2">
<a class="sendMessegeLink" onclick="open_iframe('...)" title="someText2">
<img style="padding-left:5px; vertical-align:middle" src="..."/>
<!-- WANTED ("not currently visible") ELEMENT -->someText2
</a>
<span class="remark"> someText3</span>
</td>
</tr>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tr>
</tr>
</tbody>
</table>
</div>
</div>
...
I've been trying to click the element "someText2" of class "sendMessegeLink" with :
WebElement inputElement = driver.findElement(By.xpath(".//*[#id='SomeUniqueId']/table/tbody/tr[2]/td/a"));
than :
WebElement inputElement = driver.findElement(By.cssSelector(".personalDetailsTable .sendMessegeLink"));
and than by manipulating the DOM display attribute (after reading this ) :
javascriptExecutor js = (JavascriptExecutor) driver;
WebElement w = (WebElement) js.executeScript("return document.getElementByClassName('sendMessegeLink').removeAttribute('display');");
and lastly just by Thread.sleep(5000) before accessing element in case everything isn't loaded at the DOM (in addition to driver.manage().timeouts().implicitlyWait(sec, TimeUnit.SECONDS) that I use.
I get Element is not currently visible and so may not be interacted with
Try this
WebElement tmpElement= driver.findElement(elementLocator); // Try all your combination here
JavascriptExecutor executor = JavascriptExecutor)driver;
executor.executeScript(“arguments[0].click();”, tmpElement);