I have table kind of appearance as shown below but it's not a single table. Header is in one table and rows are in another table.
The header has Primary, Language and the add button which is one table and rest of the two rows are in another table. Now I have to identify the cell using the header text. For an example, If I give 1 Language
then it has to locate the first row second cell in which Arabic is chosen. Likewise, If I give 2 Primary
it has locate the second row first column.
The HTML code is shown in the pic below. If it's possible to solve this problem, then I will give the actual code.
<div id="d78Pt30" style="width: 35em;" >
<div id="d78Pt30-head" style="">
<table id="d78Pt30-headtbl" style="table-layout: fixed;" width="100%">
<colgroup id="d78Px30-hdfaker">
<col id="d78Py30-hdfaker" style="width: 61px;">
<col id="d78Pz30-hdfaker" style="">
<col id="d78P_40-hdfaker" style="width: 50px;">
<col id="d78Px30-hdfaker-bar" style="width: 0px">
</colgroup>
<tbody id="d78Pt30-headrows">
<tr id="d78Px30" style="text-align: left;">
<th id="d78Py30" >
<div id="d78Py30-cave" >
<div ><i id="d78Py30-sort-icon"></i></div>
Primary
</div>
</th>
<th id="d78Pz30" >
<div id="d78Pz30-cave" >
<div ><i id="d78Pz30-sort-icon"></i></div>
Language
</div>
</th>
<th id="d78P_40" >
<div id="d78P_40-cave" >
<div ><i id="d78P_40-sort-icon"></i></div>
<a id="d78P040" href="javascript:;"><img src="assets/images/add.png"
align="absmiddle"></a></div>
</th>
<th id="d78Px30-bar" ></th>
</tr>
</tbody>
</table>
</div>
<div ></div>
<div id="d78Pt30-body" style="overflow: auto;">
<table id="d78Pt30-cave" style="table-layout: fixed;" width="100%">
<colgroup id="d78Px30-bdfaker">
<col id="d78Py30-bdfaker" style="width: 61px;">
<col id="d78Pz30-bdfaker" style="">
<col id="d78P_40-bdfaker" style="width: 50px;">
</colgroup>
<tbody id="d78Pi50" >
<tr id="d78P260" >
<td id="d78P360-chdextr" >
<div id="d78P360-cell" ><span id="d78P360"
><input
type="radio" id="d78P360-real" name="d78P360" checked="checked"><label for="d78P360-real"
id="d78P360-cnt"
></label></span>
</div>
</td>
<td id="d78P460-chdextr" >
<div id="d78P460-cell" ><span id="d78P460"
style="width: 225px;"><input id="d78P460-real"
autocomplete="off"
value="" type="text"
size="20"
style="width: 196px;"><a
id="d78P460-btn" ><i id="d78P460-icon"
></i></a><div
id="d78P460-pp" style="display: none;"></div></span></div>
</td>
<td id="d78Py60-chdextr" >
<div id="d78Py60-cell" >
<div id="d78Py60" >
<div id="d78Pz60-chdex" style=""><a id="d78Pz60"
href="javascript:;"><img
src="assets/images/delete.png" align="absmiddle"></a></div>
</div>
</div>
</td>
</tr>
</tbody>
<tbody >
<tr>
<td id="d78Pt30-empty" style="display: none;" colspan="3">
<div id="d78Pt30-empty-content" >No data available</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
As you can see in the HTML, there are two tables and first one is having the header and second one is having the rest of the rows.
CodePudding user response:
Since the full markup of the table was not provided, I've used the HTML at the end of the answer to illustrate the possible solutions.
Solution 1 - Hardcode the column index
If the table columns are _static, the easiest solution is to hardcode an index lookup in your code. This solution also makes it easier to deal with header cells that do not have text - eg the add icon.
For example, you know that "Language" header is always column index 1 and "Primary" is always column index 0. Therefore, you know that if you want the "Language" of a data row, it will be the 2nd cell in the row.
def cell_by_header_text(browser, data_row_index, header_text)
columns = ['Primary', 'Language', 'Add'] # must match the order on the page
column_index = columns.index(header_text)
data_table = browser.div(class: 'z-grid-body').table
data_table[data_row_index - 1][column_index] # returns Watir::Cell
end
p cell_by_header_text(browser, 1, 'Language').html
#=> "<td><select><option selected=\"selected\">Arabic</option><option>Bengali</option></select></td>"
p cell_by_header_text(browser, 2, 'Primary').html
#=> "<td><input type=\"radio\" checked=\"\"></td>"
Solution 2 - Dynamic lookup of column index
If the table columns are dynamic or you want a more general solution, you can lookup the column index from the header table.
def cell_by_header_text(browser, data_row_index, header_text)
header_table = browser.div(class: 'z-grid-header').table
column_index = header_table.tds.find_index { |td| td.text == header_text }
data_table = browser.div(class: 'z-grid-body').table
data_table[data_row_index - 1][column_index] # returns Watir::Cell
end
Solution 3 - Domain-specific collection
If you want to improve readability and have more flexibility, you could take it a step further and create a domain-specific collection for the grid:
class LanguageRowCollection
include Enumerable
def initialize(browser)
@browser = browser
end
def each
data_rows.map { |data| yield LanguageRow.new(header_row, data) }
end
def [](value)
to_a[value]
end
private
def header_row
@browser.div(class: 'z-grid-header').table.tr
end
def data_rows
@browser.div(class: 'z-grid-body').table.trs
end
end
class LanguageRow
def initialize(header_row, tr)
@header_row = header_row
@tr = tr
end
def primary_cell
@tr.tds[@header_row.tds.map(&:text).index('Primary')]
end
def primary?
primary_cell.radio.selected?
end
def set_primary(value)
primary_cell.radio.set(value)
end
def language_cell
@tr.tds[@header_row.tds.map(&:text).index('Language')]
end
def language
language_cell.select.text
end
def set_language(value)
language_cell.select.set(value)
end
def remove_cell
# Locating the 3rd column by it's image since it doesn't have text
@tr.tds[@header_row.tds.find_index { |td| td.image(class: 'add').exists? }]
end
def remove
remove_cell.link.click
end
end
def languages(browser)
grid = browser.div(class: 'z-grid')
LanguageRowCollection.new(grid)
end
You get a more readable way to get/set values:
# Get/set the language of the first row (note the 0-based index)
languages(browser)[0].language
#=> "Arabic"
languages(browser)[0].set_language('Bengali')
You also get the flexibility of locating rows based on their values:
# Get the primary language
languages(browser).find(&:primary?).language
#=> "Bengali"
# Remove the Arabic row
languages(browser).find { |l| l.language == 'Arabic' }.remove
HTML Example
The following HTML was used for the above examples.
<html>
<body>
<div id="d78Pt30" >
<div >
<table>
<tr>
<td>Primary</td>
<td>Language</td>
<td>Add</td>
</tr>
</table>
</div>
<div ></div>
<div >
<table>
<tr>
<td><input type="radio"></td>
<td><select><option selected="selected">Arabic</option><option>Bengali</option></select></td>
<td><a href="#">Minus</a></td>
</tr>
<tr>
<td><input type="radio" checked></td>
<td><select><option>Arabic</option><option selected="selected">Bengali</option></select></td>
<td><a href="#">Minus</a></td>
</tr>
</div>
</div>
</body>
</html>