I have a table:
<table>
<thead>
<tr>
<th>Header1</th>
<th>Header2</th>
</tr>
</thead>
<tbody>
<div th:if="${param1 != null}">
<td class="dripicons-checkmark"></td>
</div>
<div th:if="${param2 != null}">
<td class="dripicons-checkmark"></td>
</div>
</tbody>
</table>
param1 and param2 are coming from my controller:
model.addAttribute("param1", param1)
model.addAttribute("param2", param2)
...and they can be null or contain some info. I'm trying to show a checkmark under correct header. If param1 is not null, I want to show the checkmark under Header1 and if param2 is not null, I want to show the checkmark under Header2 and so on. The code above shows the checkmark always under Header1, if either one of the params are not null. How can I put the icon under a correct header?
If either one of your params is null, then you will only be creating one <td> cell in the <tr> row. Your table always needs two cells to match the two headings you have.
There are various ways around this. The following is one way, which I think is reasonably concise:
<tbody>
<td th:class="${param1} != null ? 'dripicons-checkmark' : null"></td>
<td th:class="${param2} != null ? 'dripicons-checkmark' : null"></td>
</tbody>
In this example, we always have two row cells.
The "if" condition is inside a th:class attribute, so there is no need for any surrounding <div> elements.
The HTML generated by this is as follows, when the first value is null, but the second value is not null:
<table>
<thead>
<tr>
<th>Header1</th>
<th>Header2</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td class="dripicons-checkmark"></td>
</tr>
</tbody>
</table>
Related
I have an html thymeleaf template where I build a table iterating over a list:
<table>
<tr>
<th>Setup Name</th>
<th>Setup Path</th>
</tr>
<tr th:each="setup : ${upgradeState.targetUpgradeSetups.setups}">
<td th:text="${setup.name}"/>
<td th:text="${setup.path}"/>
</tr>
</table>
The problem is that the element upgradeState.targetUpgradeSetups may be null, so I would like to build this table only when the element is not null.
Note: if the element upgradeState.targetUpgradeSetups is not null, then it's guaranteed for the list setups to be not null either. Hence I only need to check for the parent element.
I have tried to use the th:if statement as follows:
<tr th:if=${upgradeState.targetUpgradeSetups != null} th:each="setup : ${upgradeState.targetUpgradeSetups.setups}">
But even like that, I still get the same exception:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'setups' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:51)
at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:406)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:90)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:109)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:328)
at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:263)
... 74 more
I didn't manage to find a specific example/reference about Thymeleaf for such issue, could anyone please suggest the right way?
You need to count on Thymeleaf Attribute Precedence. According to the order, Thymeleaf will parse iteration first and only after the condition, when placed into the same tag. The code which would work for you may look like ...
<table>
<tr>
<th>Setup Name</th>
<th>Setup Path</th>
</tr>
<tbody th:if=${upgradeState.targetUpgradeSetups != null}>
<tr th:each="setup : ${upgradeState.targetUpgradeSetups.setups}">
<td th:text="${setup.name}"/>
<td th:text="${setup.path}"/>
</tr>
</tbody>
</table>
How can I, inside a th:each loop create a group of two rows instead of just one?
I know I can do:
<tr th:each="obj: ${listOfObjects}">
<td>a column with data: ${obj.id}</td>
</tr>
However, I want two <tr> elements to be created, as I would do with JSTL:
<c:forEach items="${listOfObjects}" var="obj">
<tr>
<td>${obj.id}</td>
</tr>
<tr>
<td>${obj.name}</td>
</tr>
</c:forEach>
Is there a way to achieve that with Thymeleaf?
You could use a th:block element for grouping the rows together and repeat them:
<th:block th:each="obj: ${listOfObjects}">
<tr>
<td th:text="${obj.id}"></td>
</tr>
<tr>
<td th:text="${obj.name}"></td>
</tr>
</th:block>
You can read more about th:block here
Is it possible to pass a tag/fragment to another template in thymeleaf?
Example: I want to create a basic tableview layout, and the callers template should only provide the <tbody> content that then should get injected into the tableview template layout.
This could be the table layout:
<div th:fragment="tableview (tbodyFragment)">
<table class=...>
<thead>...</thead>
<!-- the table body should be repaced -->
<tbody th:replace="${tbodyFragment}"/>
</table>
</div>
Calling template:
<tbody id="tbodyFragment">
<th:block th:each="row : ${rows}">
<tr>
<td th:text="${row.id}"/>
<td th:text="${row.firstname}"/>
<td th:text="${row.lastname}"/>
<td th:text="${row.age}" style="text-align:right"/>
</tr>
<th:block>
</tbody>
<div th:insert="~{tableview::tableview(tbodyFragment)}"/>
Of course the syntax above is invalid, but you get the idea. How could I achieve this?
It's simple as passing the fragment as id, and nest it below the th:insert tag from calling template:
<div th:insert="~{tableview::tableview(~{:: #tbodyFragment})}">
<tbody id="tbodyFragment">
...content here...
</tbody>
</div>
I am having some problems currently trying to untick checkboxes in an iframe. The situation is it is currently possible to set some checkboxes to default ticked and some not. I need 1 specific checkbox ticked, so the sensible thing to do is run a loop that iterates through all the checkboxes and unchecks them all.
Here is where I am running into issues. I will post a sample of the HTML that the checkboxes are contained in. (This isn't mine so I can't edit the HTML unfortunately).
This is how the example looks in a situation where there are 3 different types of checkbox in the iframe.
<fieldset id="testing">
<legend>testing</legend>
<table>
<tbody>
<tr>
<td class="EXAMPLE">
<table id="CHECKBOXTYPE1">
<tbody>
<tr>
<td style="vertical-align:top;white-space:nowrap;" title="">
<input id="CHECKBOXTYPE1-01" type="checkbox" value="on" onclick="DOES STUFF;"/>
</td>
<td style="vertical-align:top;white-space:nowrap;" title="">TITLE1</td>
</tr>
<tr>
<td/>
<td id="CHECKBOXTYPE2-01" style="display:none;white-space:nowrap;vertical-align:top;padding:0px;">
<table>
<tbody>
<tr>
<td style="vertical-align:top;" colspan="3">
<select id="field" style="width:100%;">
<option value="1">STUFF1 </option>
<option value="2">STUFF2 </option>
<option value="3">STUFF3 </option>
<option value="4">STUFF4 </option>
</select>
</td>
<td style="vertical-align:bottom;padding-left:6px;" rowspan="2">
<textarea id="CHECKBOXTYPE2-01-COMMENTS" cols="50" rows="2" style="margin:0px;height:50px;" type="text" onclick="DOES STUFF">Please Insert Notes...</textarea>
</td>
</tr>
<tr>
<td style="vertical-align:bottom;">
<input type="CHECKBOXTYPE2-01-BUTTON" onclick="DOES STUFF" value="<" style="height:100%;width:32px;"/>
</td>
<td style="vertical-align:bottom;">
<input id="CHECKBOXTYPE2-01-INPUT" type="input" readonly="" style="width:112px;"/>
</td>
<td style="vertical-align:bottom;">
<input type="CHECKBOXTYPE2-01-BUTTON" onclick="DOES STUFF" style="width:32px;height:100%;" value=">"/>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td class="field_label">
<table id="CHECKBOXTYPE3">
<tbody>
<tr>
<td style="vertical-align:top;">
<input id="CHECKBOXTYPE3-01" type="checkbox" title="" onclick="DOES STUFF"/>
</td>
<td style="vertical-align:top;" title="">CHECKBOX NAME</td>
<td style="vertical-align:top;">
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
The code I have attempted to iterate is
try{
for(int i=0; i < 30; i++){
WebElement relCheckBoxes = driver.findElement(By.xpath("html/body/div[3]/fieldset/table/tbody/tr[i]/td/table/tbody/tr/td[1]"));
if(relCheckBoxes.isSelected()){
relCheckBoxes.click();
}
}
}
catch(Exception e){
System.out.printf("didn't work");
}
Obviously this is not the most optimised piece of code, but right now I'm just struggling to find something that works :\ I just want to run through the checkboxes, turn off all of them, then turn on the one that I need after.
Thank you.
If you want to uncheck all the checkboxes use the following code. It is much efficient!
//Get the complex table
WebElement mainTable = driver.findElement(By.xpath("html/body/div[3]/fieldset/table"));
//Find all the input tags inside the mainTable and save it to a list
List<WebElement> checkBoxes = mainTable.findElements(By.tagName("input"));
//iterate through the list of checkboxes and if checked, uncheck them
for (WebElement checkbox : checkBoxes) {
if (checkbox.isSelected()) {
checkbox.click();
}
}
I dont see any frame inside your code. If there is a frame use the below code 1st
//switch to the frame
driver.switchTo().frame("framename/index");
Hope this helps you :)
There are a couple of problems here:
1) Your XPath is incorrect. You have:
"html/body/div[3]/fieldset/table/tbody/tr[i]/td/table/tbody/tr/td[1]"
Instead, it should be:
"html/body/div[3]/fieldset/table/tbody/tr[" + i + "]/td/table/tbody/tr/td[1]"
Otherwise, you're just looking for a table row with a non-numerical index 30 times!
2) XPath indices are 1-based rather than 0-based (crazy, I know). Since your loop starts with i=0, it starts off by trying to find the non-existent zeroth element. findElement throws an exception when it cannot locate an element that matches the search criterion, so the loop ends immediately. Try starting the loop with i=1 instead.
I have two list on my request on jsp. First one is productGroupName, and the second is products.
Now, I show these like below.
<html:form action="/priceOrder"> <table width="100%" id="tableStyle" style="font: message-box;padding: 20px;">
<logic:iterate id="productGroups" name="productGroup">
<tr>
<td>
<h3 style="background-color: #720D00; color: white;"><bean:write
name="productGroups" property="prodGroupName" /></h3>
<table width="100%" id="tableStyle" style="font: message-box; color: white; padding: 20px; background: #F15A00;">
<tr>
<td width="200px"><strong>Product Name</strong></td>
<td width="100px"><strong>How Many</strong></td>
<td><strong>Info</strong></td>
</tr>
<logic:iterate id="product" name="products">
<tr>
<c:if test="${(productGroups.prodGroupID) == (product.prodGroupID)}">
<td>
<html:checkbox property="productChecked" ><bean:write name="product" property="prodName"/></html:checkbox> <br />
</td>
<td><html:text property="quantity" styleId="check" size="5"/></td>
<td><bean:write name="product" property="prodDesc" /></td>
</c:if>
</tr>
</logic:iterate>
</table>
</td>
</tr>
</logic:iterate>
<tr align="center" style="background-color: #F15A00;"><td height="50px">
<html:submit styleId="buton" property="method"><bean:message key="button.order" /></html:submit>
</td></tr>
<tr><td></td></tr>
</table></html:form>
As you see firstly I iterate productGroupNames, showing if productID is equal to productGroupID under productGroupName. But I have a problem on getting check box and quantity info. I need which product is checked and how many that is wanted.
Instead of doing a form submit directly, submit it through a JS function. In your JS function, since you're iterating your list and giving the checkbox and text field the same name, you'll get an array with the same name.
That is you'll get an array of the IDs. You can get the index of the selected checkbox, get the quantity, get the corresponding list element and populate separate hidden form variables with the value. Then submit it.
An alternative approach would be to have a hidden variable associated with each checkbox which provides some mapping between the list and the checkbox.
I don't do Struts, but their documentation at least says that you need the <html:multibox> for this.