htmx: How to swap table row with hx-swap-oob? - htmx

I want to use hx-swap-oob to replace a table row of the existing page "out of band".
in browser:
<table>
<tr id="offer_1">....</tr>
<tr id="offer_2">....</tr> (old)
<tr id="offer_3">....</tr>
</table>
From Server to client:
<table hx-swap-oob="outerHTML:#offer_2" hx-select="#offer_2">
<tr id="offer_2"> .... </tr> (new)
</table>
But up to now this is the result:
<table>
<tr id="offer_1">....</tr>
<table hx-swap-oob="outerHTML:#offer_2" hx-select="#offer_2">
<tr id="offer_2"> .... </tr> (new)
</table>
<tr id="offer_3">....</tr>
</table>
I guess hx-select does not get evaluated when htmx get this snippet from the server.
How can I swap a row out-of-band?

Take a look at the new extension multi-swap.
https://htmx.org/extensions/multi-swap/
It allows swapping multiple elements marked with the id attribute.
For each element it is possible to choose which swap method should be used.

This does work:
<tr hx-swap-oob="true" id="offer_2"> .... </tr> (new)
But it has a drawback:
You need to modify the method which creates this row. Depending on your context, you might already have a method for this. Why modify this method, just because the result of this method should get used out-of-band?
If you use Django, this snippet could get used to add the hx-swap-oob attribute after the HTML got created:
def add_oob_attribute(html):
"""
I would like to avoid this ugly hack
https://github.com/bigskysoftware/htmx/issues/423
"""
assert isinstance(html, SafeString)
new, count = re.subn(r'(<\S+)', r'\1 hx-swap-oob="true"', html, count=1)
if not count == 1:
raise ValueError(f'Could not add hx-swap-oob: {html}')
return mark_safe(new)
I created an issue to find a better solution in the future:
https://github.com/bigskysoftware/htmx/issues/423

Related

How do I use chained `css()` calls so the selector in the second call uses the first call as the context?

I'm processing a table row-by-row and need to sniff the ids of the rows:
<table id="tbl">
<tr id="row_1">
<td id="cell_1">...</td>
</tr>
<tr id="row_2">
<td id="cell_2">...</td>
</tr>
</table>
So my code looks something like:
def parse_table(self, response):
rows = response.css('#tbl > tr')
for row in rows:
rowid = row.css('::attr(id)')
if rowid.extract_first().startswith('row'):
...
However, this way, the second call to .css() gives me IDs of all the descendants of row, not just its direct children. I.e. for the above example HTML, it returns "cell_1" as well as "row_1". How do I scope the chained css() call so it only acts on direct children of the given row?
I've tried using the :scope pseudo-class but that doesn't seem to be supported by Scrapy, and :root gives me no results.
Alternately, can I just get the value of the id attribute without going through CSS?
I can show you how to use XPath for the same task:
def parse_table(self, response):
for row in response.xpath('//*[#id="tbl"]/tr'):
rowid = row.xpath('./#id').extract_first()
if rowid.startswith('row'):
...

Populating table with object containing an array in vuejs?

I am trying to populate table with an object which contains an array. I am able to successfully do that but I want each task name to have its own row right now they are coming in a single row.
{level_image :"image"level_name:"1"task_name: ["game","taskgame","jenga"]}
<tr v-for="tel in result" :key="tel.level_image" :pey="tel.level_name">
<td>{{tel.level_image}}</td>
<td>{{tel.level_name}}</td>
<td v-for="task in tel.task_name">{{task}}</td>
</tr>
You're missing the obvious: if you want each one to have its own row, you need to put the v-for in a <tr> tag (like you did for result). Exactly how you deal with the <td>s is up in the air, but it might go like this:
<tr v-for="tel in result" :key="tel.level_image" :pey="tel.level_name">
<tr v-for="task in tel.task_name">
<td>{{tel.level_image}}</td>
<td>{{tel.level_name}}</td>
<td>{{task}}</td>
</tr>
</tr>
Or if you mean you want each one to be on a separate line within a table cell, it could be
<tr v-for="tel in result" :key="tel.level_image" :pey="tel.level_name">
<td>{{tel.level_image}}</td>
<td>{{tel.level_name}}</td>
<td><div v-for="task in tel.task_name">{{task}}</div></td>
</tr>
The main idea is that you want the v-for to be associated with the type of tag that creates the entity you want each task in.

check text is present in table (selenium IDE)

I am trying to check that the text "AUTOTEST" is present somewhere in my HTML table "tableTest".
In selenium IDE, i put this code :
<tr>
<td>verifyTextPresent</td>
<td>//table[#id='tableTest']</td>
<td>AUTOTEST</td>
</tr>
Here is the code of the HTML table :
<table id="myTable">
<tr>
<td>AUTOTEST</td>
<td>TEST</td>
</tr>
<tr>
<td>UOI</td>
<td>TEST</td>
</tr>
</table>
But the assertion always return false whereas text is well present in the table.
Which command can i use to check that text is present in my table ?
I think the reason for this is that you're trying to verify one bit of text using the entire table as a locator, rather than the specific section that contains the text you're looking for, as a result it isn't matching because you have other content within the table, and your verify step is looking for an exact match. You'd need to put in wildcards around AUTOTEST in your selenium script, that way it will just look to make sure that it is present somewhere within the table.
Script and log testing against the HTML code you provided for the table.
<tr>
<td>verifyText</td>
<td>css=table</td>
<td>*AUTOTEST*</td>
</tr>
[info] Playing test case Untitled
[info] Executing: |verifyText | css=table | *AUTOTEST* |
[info] Test case passed
VerifyTextPresent is depracted, VerifyText will do what you want:
<tr>
<td>verifyText</td>
<td>//table[#id='myTable']</td>
<td>*AUTOTEST*</td>
</tr>
The other thing to note is the text is the FULL text, so in this case you need to use a glob and use the * which serves as a wildcard.
Note: by the way you could also just specify the id (and not the full xpath) like this:
<tr>
<td>verifyText</td>
<td>myTable</td>
<td>*AUTOTEST*</td>
</tr>

Selenium XPath - Ignore element amongst table

I have an issue with selecting a table to be read in Selenium.
I have a table in which there is two 'tr' elements inside the 'thead', and I need to find a way to ignore the first of these.
Here is the code:
<table class="noselect">
<thead>
<tr>
<th> </th>
<th class="number IOL">Interest Rates</th>
<th class="number IO">
</tr>
<tr>
<th>Description</th>
<th class="number">Value</th>
<th class="number">Percentage</th>
</tr>
</thead>
<tbody>
<tr>
<tr class="">
<tr class="">
<tr class="">
<tr>
<tr>
</tbody>
</table>
Using Selenium I will ask it to record the value of a certain row and column . This will then look at the Table element I will give it (hopefully using an XPath I can get working in this case), look at the thead and record the headers of each column. In this case that I am struggling with, the fact there is an extra 'tr' at the top of this table gets in the way of this process.
This is how the element is currently used:
[TableAlias("Detailed table")]
protected virtual IWebElement DetailedTable()
{
return Driver.FindElement(By.XPath("//table[#class='noselect']"));
}
I have tried many different ways which I can't get to work, but the gist of what I've been going for is:
//table[#class='noselect movements']/thead/tr/th[not(text()='Interest Rates')]/../../..
Here I'm stuck on going to the 'tr' element, telling it not to use it then backing out, but that selects it back again - and even that doesn't unselect the whole 'tr' element. It doesn't seem to help (to me) that the 'tr' element I'm trying to remove is blank with no class or defining features.
Is there a way of selecting the entire table except for the first 'tr' element in 'thead' as one element?
combine two xpathes. The 1st xpath take thead without the 1st tr and the 2nd tbody
//table/thead/tr[not(position()=1)] | //table/tbody
In your function that processes the THEAD tag, get the collection of TRs and start with [1] (skipping [0]) and process the rest.

Clicking other cell's child element in Selenium WebDriver Java

What is the code to be used to click the "a" element by looking first for the "td" that contains certain texts?
<table>
<tbody>
<tr>
<td><a class="link">link</a></td>
<td>1st</td>
</tr>
<tr>
<td><a class="link">link</a></td>
<td>2nd</td>
</tr>
</tbody>
</table>
I used this code but it doesn't work.
driver.findElement(By.xpath("//td[contains(text(), '1st')]/following-sibling::a[#class='link']")).click();
Try this xPath //td[contains(text(), '1st')]/../td/a[#class='link'].
Your mistake comes from the axis "following-sibling". The tag a is not a sibling of the td tag. I use .. to go up, then select td again and then a.
I tested the xPath using http://www.xpathtester.com/xpath. It works. Beware that every browser comes with their own xPath implementation, therefore it could behave a bit differently.
However, as there is nothing exotic in the xPath expression, I don't expect any problem.