Use selenium webdriver to extract dynamic table displayed on the website - javascript

I am trying to parse a website where table content is loaded through javascript-ajax call..
function buildTable() {
// render spinner over dataset summary table
var overlay = document.getElementById("summary");
enableOverlay(overlay, true, true, "30px");
// request dataset summary from server
$.ajax({
url: "/ProteoSAFe/MassiveServlet",
data: { "function":"", "mid":dataset_name },
type: "GET",
cache: false,
complete: function(data) {
var stats = JSON.parse(data.responseText);
var filesize = document.getElementById("filesize");
filesize.innerHTML = stats.filesize;
}
In HTML :
<table>
<table>
<tr>
<td>Number of Files:</td>
<td id="filecount"></td>
</tr>
<tr>
<td>Total Size:</td>
<td id="filesize"></td>
</tr>
<tr id="spectra_row" style="display:hidden">
<td>Spectra:</td>
<td id="spectra"></td>
</tr>
<tr>
<td>Subscribers:</td>
<td id="subscribers"></td>
</tr>
I am using below code in selenium:
List<WebElement> tables = div.findElements(By.tagName("table"));
wait.until(ExpectedConditions.visibilityOfAllElements(tables));
for (WebElement table : tables) {
List<WebElement> allRows = table.findElements(By.tagName("tr"));
for (WebElement row : allRows) {
List<WebElement> cells = row.findElements(By.tagName("td"));
for (WebElement cell : cells) { System.out.println("content >> " + cell.getText());
}
}
}
My question is : Its extracting only couple of table cells ..I want to extract content of all the table.
Is there any other way to extract the table content. Please advise.

Related

Add Link Column to DataTable After Ajax Call MVC

On my view page I have a table (from a partial view) and a form. I am using ajax to submit the form to my webapi controller.
On success I would like to add what was entered in the textbox to the first column, and links to Edit and Delete in the second column of a new row.
As of right now I am only working on the Edit link.
Here is my partial view table:
<table id="Table" class="table table-bordered">
<thead>
<tr>
<th class="col-md-6">
#Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
</thead>
#foreach (var item in Model)
{
<tr>
<td class="col-md-6">
#Html.DisplayFor(modelItem => item.Admin)
</td>
<td class="col-md-6">
#Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
Here is my form jquery.ajax:
var table = $("#Table").DataTable({
"aoColumnDefs": [
{ "bSortable": false, "aTargets": [1] },
{ "bSearchable": false, "aTargets": [1] }
]
});
$("form").submit(function(e) {
e.preventDefault();
$.ajax({
url: infoGetUrl,
method: "post",
data: $("form").serialize()
}).success(function (data) {
var editLink = document.createElement('a');
editLink.href = "/controllerName/Edit/" + data.id;
editLink.text = "Edit";
table.row.add([
$("#Textbox").val(),
editLink
]).draw();
}).error(function(jqXHR, textStatus, errorThrown) {
console.log("error");
});
});
The problem is that when this renders I get this:
It is not clickable and renders like this:
<tr class="even" role="row">
<td class="sorting_1">John.Doe</td>
<td>http://localhost:61888/controllerName/Edit/15</td>
</tr>
As you can see, it is not rendered in an a tag, and I don't need the http://localhost:61888 part of the link.
How can I resolve this?
try creating link as:
var link = <a href='/controllerName/Edit/' + data.id>EDIT</a>
With pur JS:
var link = document.createElement('a');
link.textContent = 'Edit';
link.href = "/controllerName/Edit/" + data.id;
you just need to place this inside your td.
If you want to remove 'http://localhost:61888' you can just use replace to change your localhost by un empty string. Or split your string and just keep the second part

How I can order data pre date

I would like to know how I can do order data from API pre-date very time.
How its should be:
<table>
<tr>
<th>2017-02-17</th>
</tr>
<tr>
<td>some date</td>
<td>some date</td>
<td>some date</td>
</tr>
<tr>
<th>2017-02-15</th>
</tr>
<tr>
<td>some date</td>
<td>some date</td>
<td>some date</td>
</tr>
</table>
example:
URL API: http://api.tradingeconomics.com/calendar?c=guest:guest
My code:
$.ajax({
url: "url",
type: "Get",
datatype: "JSON",
contentType: "application/json",
error : function (data) { console.log("error:" + data) },
success: function (response) {
response.forEach(function (data) {
$('.top_table').append(
"<tr>" +
"<th>DATE</th>" +
"</tr>" +
"<tr id='content'>" +
"<td>some text....</td>" +
"<td>some text....</td>" +
"<td>some text....</td>" +
"<td>some text....</td>" +
"</tr>"
);
});
console.log(response);
}
});
But its print like:
date
result
date
result
How I can do it?
I don't know if I've understood your question very well, but I think that could give you some tips.
Your API returns an Array of Objects if you make and Ajax GET request, so you can order this Array before inserting the content into the DOM:
The next example order the data in descending order comparing the Date parameter, there is another date parameter called LastUpdate, I don't know if you want to use it in your logic.
$.get("https://api.tradingeconomics.com/calendar?c=guest:guest", function (data) {
//---Order the array received from the server
data.sort(function (a, b) {
return (new Date(a.Date)) - (new Date(b.Date));
});
//---The data is ordered, you can insert it into the DOM
});
In the other hand, your code inserts a row with the header content and a row with the body content in each iteration, this is not correct. You need to add all the header texts in a single row and each item of the Array needs to be inserted in separated rows.
Here you have a working example to give you an idea of the process:
https://jsfiddle.net/elchininet/ym8qp415/
EDIT: Seeing your comments, I understand now that you want to grouping the data not just ordering it. I recommend you to use the reduce method of the Array class to create a new data separated by dates and after that you can insert the data in the table:
var regdate = /^(\d{4}\-\d{2}\-\d{2})T(\d{2}:\d{2}:\d{2})$/;
//---Sort the data from the server
data.sort(function (a, b) {
return (new Date(a.Date)) - (new Date(b.Date));
});
var group = data.reduce(function (before, current) {
var day = current.Date.replace(regdate, "$1");
var hour = current.Date.replace(regdate, "$2");
if (!before[day]) {
before[day] = [];
}
current.Hour = hour;
before[day].push(current);
return before;
}, {});
//---The data is ordered and grouped, you can insert it into the DOM
Working example with fake data (Because of the example in the API returns only one day):
http://jsfiddle.net/elchininet/nvv4fnon/
Without a plugin, this is going to be difficult to achieve unless the "calendar" information is pulled from a database, it may be worth sorting in PHP, loading and displaying the data in jQuery
<script type="javascript">
$(function() {
$("BODY").on("click", "TH[data-orderby]", function() {
var order = $(this).data("orderby") || "date";
var parent = $(this).parents("table").parent();
$.ajax({
url: 'calendar?c=guest:guest',
data: 'order-by=' + URLEncode(order),
type: 'POST',
success: function(response) {
parent.html(response);
},
error: function(event, request, settings) {
console.warn("Ajax Error", request);
}
})
});
});
</script>
<div class="parent">
<table>
<thead>
<tr>
<th>Heading</th>
<th data-orderby="date">Date</th>
<th>Title</th>
<th data-orderby="last_updated">Last Updated</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data</td>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</tr>
</tbody>
</table>
Because we use $("BODY").on("click", "TH[data-orderby]"), even when the data is reloaded from the server, the sort functionality will remain.
I hope this helps.

Unable to add row in the middle of jQuery datatables(with FIDDLE)

I am trying to add new rows to the table using the rows.add() function in the DataTables API. The data is coming from the server using AJAX call.
Here is an example to work upon - FIDDLE
My Table Structure is follows:
<table id="myTable">
<thead>
<th>
Id
</th>
<th>
Name
</th>
<th>
Designation
</th>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#item.Number
</td>
<td>
#item.Name
<img id="imgA" onclick="AddNewRows();" class="iterationChild" src="#Url.Content("~/Images/plus.png")" alt="expand/collapse" />
</td>
<td>
#item.Designation
</td>
</tr>
}
</tbody>
</table>
Corresponding Javascript function:
function AddNewRows() {
$.ajax({
type: 'GET',
url: '#Url.Action("NewRows", "Home")',
dataType: "json",
async: true,
success: function (data) {
var table = $('#myTable').DataTable();
for (var i = 0, l = data.length; i < l; i++) {
//how to add it just after the current row clicked
table.row.add([
data[i].Number,
data[i].Name,
data[i].Designation
]).draw();
}
},
error: function (result) {
alert('error');
}
});
}
I want to be able to add the new row after the row which is clicked. Here it is adding at the end of the table(last rows).
Assuming every row as a unique id, try passing the current row clicked id into your function as a parameter. Example:
function AddNewRows(id) {
var my_row = document.getElementById(id);
...

How do I get the id for a <tr> in when using jQuery DataTables?

I am adding a button that will "approve" all rows in the table (call a URL to process the record). I generate the table then attach the DataTable to the prefilled table. On each tr I have the id number of the record.
<tr id="11309742">
<td>blah</td>
<td>blah</td>
<td>blah</td>
</tr>
<tr id="11309743">
<td>blah</td>
<td>blah</td>
<td>blah</td>
</tr>
Here is what I have so far:
$.each(table.fnGetData(), function (i, row) {
var id = $(this).attr("id");
$.get(myUrl, { id: id },
function (json) {
if (json.Sucess) {
// TODO remove from the page
}
}, "json");
});
var id = $(this).attr("id"); worked before I switched to the datatable plugin (and I know it won't work now). Everything I have seen is either setting the id or getting the index from a click in the row. How do I get that id attribute in a loop?
Instead of using .fnGetData(), I should have used .fnGetNodes().
$.each(table.fnGetNodes(), function (i, row) {
var id = $(this).attr("id");
$.get(myUrl, { id: id },
function (json) {
if (json.Sucess) {
//table.fnDeleteRow(i);
}
}, "json");
});
Now it works as expected.

Dynamic table column update by id, done right?

I am kinda new to Ajax/Json so I would like to know if the following is at least near to the best practice. The goal is to update specific columns (in this case quantity and price) of a table every x seconds.
I got a HTML table defined like this:
<table id="#edition_table>
<tbody>
<tr>
<td class="name">Lightning Bolt</td>
[...]
<td class="qty">2</td>
<td class="price">$4.99</td>
<tr>
<tr>
<td class="name">Fireball</td>
[...]
<td class="qty">0</td>
<td class="price">$0.07</td>
<tr>
[...]
</tbody>
</table>
And a JS function defined like this:
function edition_update(edition)
{
var table_rows = $('#edition_table').find('tbody tr td.name a');
$.ajax({
type: 'GET', url: 'ajax_edition_update.php', data: { edition : edition }, dataType: 'json',
success: function(json_rows)
{
var new_qty, new_price;
table_rows.each(function(index) {
var td_id = $(this).attr('href').replace('?card=', '');
for (i in json_rows) {
if (json_rows[i].card_id == td_id)
{
new_qty = json_rows[i].qty;
new_price = json_rows[i].low_price;
break;
}
}
var parent_tr = $(this).parent().parent();
parent_tr.find('td.qty').text(new_qty);
parent_tr.find('td.price').text(!isNaN(new_price) ? '$' + new_price : new_price);
});
}
});
setTimeout(edition_update, 30000, edition);
}
The PHP file returns a JSON including card_id, qty and low_price.
This does work fine. I guess I could set up a data-id=[card_id] on the class=name td to get rid of the .replace, but that kinda blows up the html footprint as the id is already present.
The real question is whether any performance improvements (especially regarding the two loops) are possible or necessary? The target number of rows per table is arround 500 and the content and order is totally dynamic/unpredictable, of course.

Categories