I have the following table:
<h1>Selected Shakespear Plays</h1>
<table>
<thead>
<tr>
<th>Title</th>
<th>Category</th>
</tr>
</thead>
<tbody>
<tr>
<td>As You Like It</td>
<td>Comedy</td>
</tr>
<tr>
<td>All's Well that Ends Well</td>
<td>Comedy</td>
</tr>
<tr>
<td>Henry V</td>
<td>History</td>
</tr>
</tbody>
</table>
And then the below script that uses XPath expressions. I believe that when the book I am following was published, XPath was built into jQuery, but it has since been moved out into the jquery-xpath plugin.
$("tr:not([th]):odd").addClass("odd");
$("tr:not([th]):even").addClass("even");
$("td:contains('Henry')").addClass("highlight");
$("thead tr").addClass("table-heading").removeClass("even");
This is intended to add the classes odd and even to all tr elements that don't contain a th element, i.e. to all rows except the first, header row. It does not work, the header row, even with th elements still gets the class even. This is why I had to add .removeClass("even"); to the last line of code.
Is the XPath query not([th]) or just [th]? Then, how do I translate this jQuery "XPath statement":
$("tr:not([th]):odd").addClass("odd");
to a standard jQuery statement that fetches all tr that don't contain any th?
Related
I'm trying to iterate through table rows and get each row which includes a specific value,
but it doesn't work for me.
I'm using .each() to iterate the rows and .within() on each $el,
inside that, I use cy.get('td').eq(1).contains('hello') but I the get assertion error:
Timed out retrying: Expected to find content: 'hello' within the element: <td> but never did.
when I console.log cy.get('td').eq(1) it yields the desired cell in each row and the test passes, so I don't understand why chaining .contains() doesn't work...
it('get element in table', () => {
cy.visit('http://localhost:3000/');
cy.get('tbody tr').each(($el) => {
cy.wrap($el).within(() => {
cy.get('td').eq(1).contains('hello') // contains() doesn't work
})
})
});
<table>
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tbody>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>hello</td>
<td>$80</td>
</tr>
<tr>
<td>$10</td>
<td>hello</td>
</tr>
</tbody>
</table>
should('have.text', text) should work
cy.get('td').eq(1).should('have.text', 'hello')
If there's whitespace around text, use contain.text
cy.get('td').eq(1).should('contain.text', 'hello')
The simple answer is: don't :)
To be more specific use html attribute selection instead. The convention is to have an attribute named data-cy. Furthermore, I discovered it convenient to have a data-cy-identifier for when selecting specific rows. Since I'm not sure what you're trying with your code, I'll use a similar example that can hopefully get you going:
<table data-cy="expences">
<tr>
<td data-cy="month">January</td>
<td data-cy="price">$100</td>
</tr>
<tr data-cy="discounted">
<td data-cy="month">Feburary</td>
<td data-cy="price">$80</td>
</tr>
<tr data-cy="discounted">
<td data-cy="month">March</td>
<td data-cy="price">$10</td>
</tr>
</table>
You can of course do all sorts of combinations of this, but now you can do more specific and useful selections, such as:
cy.get('[data-cy="expenses"]').find('[data-cy="discounted"]').find('[data-cy="price"]').should(...)
And similar. This is flexible, because it reflects the structure of your data, and not the presentation, so you can change this to a list or whatever later. It avoids selecting of volatile things, so it's also more robust. It also uses a hierarchy rather than overly specific selectors.
The idea of adding things like data-cy-identifier allows you to do selections by ID (you can propagate it using javascript, angular, vue or whatever you use) and then checking things like the contents of a row with logically related items.
Hope it can get you going. Also I can recommend reading: https://docs.cypress.io/guides/references/best-practices.html
I'm trying to write a regular express that will capture an HTML table (and all it table data) that has a particular class.
For example, the table has a recapLinks class, its comprised of numerous table rows and table data and then terminated with . See below:
<table width="100%" class="recapLinks" cellspacing="0">
[numerous table rows and data in the table.]
</td></tr></tbody></table>
I'm using javascript.
The regex to capture this is pretty simple, if you can guarantee that there are never nested tables. Nested tabled become much trickier to deal with.
/<table[^>]*class=("|')?.*?\bCLASSNAMEHERE\b.*?\1[^>]*>([\s\S]*?)</table>/im
For instance, if an attribute before class had a closing > in it, which isn't likely, but possible, the regex would fall flat on it's face. Complex reges can try to prepare for that, but it's really not worth the effort.
However, jQuery all by itself can make this a breeze, if these elements are within the DOM. Regex can be easily fooled or tripped, deliberately or accidentally but that's why we have parsers. JQuery doesn't care what's nested or not within the element. It doesn't care about quote style, multiline, any of that.
$(document).ready(function () {
console.log($("table.myClassHere").prop("outerHTML"))
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table class="myClassHere">
<tr>
<td>Book Series</td>
</tr>
<tr>
<td>Pern</td>
</tr>
<tr>
<td>Hobbit</td>
</tr>
</table>
<table class="otherClassHere">
<tr>
<td>Movies</td>
</tr>
<tr>
<td>Avengers</td>
</tr>
<tr>
<td>Matrix</td>
</tr>
</table>
I'm trying to get jquery.dataTables plug in to work in MVC5.
I have added everything(library and css) and included in my bundles correctly and can verify that all is there and it works by making a second table using straight html tags. That one shows and has the dataTables base functionality. But the table I am making dynamically gets the following error:
Unhandled exception at line 669, column 8 in .../Scripts/jquery.dataTables.js
Unable to get property 'className' of undefined or null reference.
I have verified that my table id is correct.
--Fixed
-- Not sure how this works. But I found the problem/solution accidentally.
I'm going to submit this anyway in case what I found is useful.
The THead section had one empty cell. (a <td></td> pair) that made the TBody section not match in count of # of cells. It would work by either adding another empty Body cell or removing the THead cell. Clearly these two items have to match one for one.
There shouldn't be any empty <th>, enough <td> to match the number of the <th> should be added. Your solution is correct.
The table generated by the visual studio scaffolding does not has a
<thead> or <tbody> tags.
The default structure of the generated table is:
<table>
<tr>
<th>...</th>
<th>...</th>
<th></th> <!-- the EMPTY header column -->
</tr>
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
.
.
.
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
</table>
Note that the last header column is empty by default since in the child rows it has the CRUD commands:
Edit | Details | Delete
For DataTables to work, the <thead> is compulsory and <tbody> is optional. When you are going to add the <thead> tag, its better to add the <tbody> tag also just for readability/symmetry [IMHO].
With the current version of the DataTables (1.10.9), it working fine with ONLY adding the <thead> tags.
The minimum required structure is:
<table>
<thead>
<tr>
<th>...</th>
<th>...</th>
<th></th> <!-- it will work -->
</tr>
</thead>
<tbody> <!-- optional, just for readability -->
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
.
.
.
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
</tbody>
</table>
Source: Just re-tested all of these points.
I am have a rails app that I am writing cucumber test for. I am trying to get a number out of specific row so I can assert against it. I have a table that looks like this:
<table class="table table-striped" id="kids">
<thead>
<tr>
<th>Name</th>
<th>Balance</th>
<th></th>
</tr>
</thead>
<tbody>
<tr data-link="/kids/2">
<td>Jason</td>
<td>
<span>$</span>
<span class="money">1.00</span>
</td>
</tr>
<tr data-link="/kids/3">
<td>Neely</td>
<td>
<span>$</span>
<span class="money">0.50</span>
</td>
</tr>
</tbody>
</table>
I need to select a td that has a specific name, and then get the balance from the span in the following td. I am sure there is a way to do this with Xpath, but I cannot figure it out. Any help would be great.
You asked for XPath so here it is:
//td[preceding-sibling::td[text()='Neely']]/span[#class='money']
Note that XPathes aren't very readable and it may be better to use Capybara's ruby methods instead:
tr = find('tr', text: 'Neely')
tr.find('.money').text
I am trying to put a div inside of a table however, it will not go across multiple rows.
Here is the code I am using:
<table>
<tr>
<td><div id="test"></td>
</tr>
<tr>
<td>row 2 stuff</td></td>
</div>
</table>
I have multiple rows that are dynamically added on a button click. I would like each group of dynamically added rows to be inside of a div for easy removal.
The problem is FireFox is automatically closing the div tag in the same cell. At the very end, it is moving my closing to the end of the first cell.
Latest tag opened should be closed first to get the perfect result.
Your code should look somehow like this:
<table>
<tr>
<td><div id="test"></div></td>
</tr>
<tr>
<td>row 2 stuff</td>
</tr>
</table>
You cannot wrap a <div> tag around table elements like that. If you would like to keep an easy reference to each row, consider keeping references to all of the newly-added rows, or add a class to them for later access.
Your markup does not abide by html standards in the sense that you are imporperly nesting. If you want to add a row use the following formation
<table>
<div id="test">
<tr>
<td></td>
</tr>
<tr>
<td>row 2 stuff</td></td>
</tr>
</div>
</table>
If you notice, I grouped the two rows within one div. Even this is ill advised as you are nesting a div within a table. A more convenient solution would be to assign a class to the divs you want to group together like so:
<table>
<tr class="test">
<td></td>
</tr>
<tr class="test">
<td>row 2 stuff</td></td>
</tr>
</table>
Here the rows I want to group together are assigned a common class. So if I were to select them with say Jquery, I would do :
$("tr.test")
Hope that helps!
Html tags must be strictly within another tag. The following markup is therefore not allowed:
<b>this <i>is a</b> test</i>
Your markup breaks the same rule.