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>
Related
I'm working on a template that will group results from a saved search building on these very helpful stackoverflow posts:
How to remove duplicate elements in a array using freemarker?
How can I group a list in an advanced pdf/html sheet in netsuite/freemarker?
The template I've created works fine for me, but when a different user tries to print with it they get an "unexpected error" from Netsuite, and when I logged into that user's account and tried to open the template and save it, I got this error:
The template cannot be saved due to the following errors:
Exception during template merging.com.netledger.templates.TemplateServiceException: Exception during template merging.java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
This other user has the same Netsuite admin role I do, and is using the same browser (Firefox). I even logged into her Netsuite account on my computer in Firefox and replicated the error, so it seems tied to her NS account(?).
My template is meant to simply group and add page breaks to the results of a saved search that returns salesperson commissions per transaction. Here is the code:
<body padding="0.5in 0.5in 0.5in 0.5in" size="Letter-landscape">
<#assign entitygroup = []>
<#list results as group><!--if the saved search results weren't sorted, they should have been be sorted here-->
<#assign groupID = group.formulatext> <!--"formulatext" is the sales rep or partner or dept, from the saved search-->
<#if entitygroup?seq_contains(groupID)><!-- do nothing / don't add it to the sequence-->
<#else><#assign entitygroup = entitygroup + [groupID]><!--add this entity to the sequence so it will be skipped next time -->
<table>
<tr><td colspan="9" style="font-weight:bold; font-size:12px;">${group.formulatext}</td></tr>
<tr>
<th style="width:10%;">${group.tranid#label}</th>
<th style="width:10%;">${group.trandate#label}</th>
<th style="width:10%;">${group.closedate#label}</th>
<th style="width:20%;">${group.companyname#label}</th>
<th align="right" style="width:10%;">${group.netamountnotax#label}</th>
<th align="right" style="width:10%;">${group.totalcostestimate#label}</th>
<th align="right" style="width:10%;">${group.tranestgrossprofit#label}</th>
<th align="right" style="width:10%;">${group.formulapercent#label}</th>
<th align="right" style="width:10%;">${group.formulacurrency#label}</th>
</tr>
<#assign total_tot = 0>
<#assign total_cost = 0>
<#assign total_profit = 0>
<#assign total_comm = 0>
<#list results as result>
<#if result.formulatext == groupID><!-- if the "entity" (rep, partner, dep) matches the current group-->
<tr>
<td style="width:10%;">${result.tranid}</td>
<td style="width:10%;">${result.trandate}</td>
<td style="width:10%;">${result.closedate}</td>
<td style="width:20%;">${result.companyname}</td>
<td align="right" style="width:10%;">${result.netamountnotax}</td>
<td align="right" style="width:10%;">${result.totalcostestimate}</td>
<td align="right" style="width:10%;">${result.tranestgrossprofit}</td>
<td align="right" style="width:10%;">${result.formulapercent}</td>
<td align="right" style="width:10%;">${result.formulacurrency}</td>
</tr>
<#assign total_tot = total_tot + result.netamountnotax>
<#assign total_cost = total_cost + result.totalcostestimate>
<#assign total_profit = total_profit + result.tranestgrossprofit>
<#assign total_comm = total_comm + result.formulacurrency>
</#if><!-- if the "entity" (rep, partner, dep) matches the current group-->
</#list><!--loop for the lines data-->
<tr style="font-weight:bold;">
<td> </td>
<td> </td>
<td> </td>
<td align="right"><strong>Totals:</strong></td>
<td align="right">${total_tot}</td>
<td align="right">${total_cost}</td>
<td align="right">${total_profit}</td>
<td> </td>
<td align="right">${total_comm}</td>
</tr>
</table>
<pbr />
</#if>
</#list><!-- loop for the "entity" grouping / goes back up to assign the next group-->
</body>
Any help is greatly appreciated, including taking a different approach to this problem!
[Additional info after more testing:]
As I've tried to run this down it seems that the way I'm doing my comments might have something to do with the out of bounds error, perhaps causing the template editor to think I've left out something so the query on the array had no results?
Logged in as the other admin user I deleted the entire body of my template, saved, then re-added it, and the error did not reoccur. Maybe the template engine reinterpreted my comments correctly (or as I intended)?
I've run into this error on another template now and re-did all of my comments in the freemarker way ("<#--") and again it stopped throwing the error, so that's a little more conclusive.
I hope this is helpful to somebody. I'm still working on these templates, so I'll update here if I get a more definitive answer.
Your error is likely because you are trying to save your template as an email template of some sort but are using N/render.TemplateRenderer and not N/render.mergeEmail.
I just store my custom templates as files to avoid validation errors on save.
Prior to saving I use https://try.freemarker.apache.org/ where running the template takes some time.
Unexpected errors generally mean a syntax error or some data that you are expecting isn't there. You might try logging your non-record data sources or have the user who is seeing the error try running your saved search directly to see if the UI reports issues accessing the data.
After working with this and another complex template I feel pretty confident that the inconsistent behavior I noted in my question was caused by using the wrong commenting tags: <!-- instead of <#--. Netsuite's template editor encourages the html-style comment by putting the text in a consistent brownish color (when using freemarker comments the text colors seem to ignore the comment tag completely) so it's a bit misleading. At least for my templates changing all the comments to the <#-- tag saved the day.
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>
In my java web application, I have a data table called "sell"
sell(id_sell,id_buyer,id_product,date,final_price,shipping_price,sales_tax)
I have created a jsp page which display some information about the user, such as the products which won at the auction; these products are described by "sell". In this page I have to use jstl library and my idea is to use 'c:forEach' tag to iterate every row of the table.
Here is my code:
<table class="table table-bordered">
<thead>
<tr>
<th>Product</th>
<th>Date</th>
<th>Final Price</th>
<th>Shipping Price</th>
<th>Salex Tax</th>
</tr>
</thead>
<tbody>
<c:forEach var="s" items="${sell}">
<tr>
<td><c:out value="${s.id_product}"/></td>
<td><c:out value="${s.date}"/></td>
<td><c:out value="${s.final_price}"/></td>
<td><c:out value="${s.shipping_price}"/></td>
<td><c:out value="${s.sales_tax}"/></td>
</tr>
</c:forEach>
</tbody>
</table>
But this code shows only an empty table. Where am I doing wrong? Do I have to import something?
From your servlet, load the needed data from your data source, and add it to a scope. Your JSP will then be able to access it through an EL expression. For example, to add data in the request scope:
List<> data = yourDao.list();
request.setAttribute("sell", data);
About your comment on your own question, use the session scope wisely. Good practice is to use the smallest scope possible.
I have the html page, and me need find some elements with tag a 'table', but such tables maybe more than one, and they don't have id or class name.
Example:
<table>
<tbody>
<tr>
.....
<table>
<tbody>
<tr>
.....
<table>
<tbody>
<tr> <-------BINGO!
.....
How i can it's do with help HtmlUnit?
Thanks...
Use HtmlPage.getElementsByTagName("table") and iterate over the returned list of HtmlTable objects until you find the table you want to find.
Spring MVC Error Messages
Hello, Spring Fellows,
I have a form that is validated by the Spring Validation once submitted. Each field on the form may contain multiple errors messages if validation fails, so error messages are displayed below the field, not next to it. Here's the code snippet.
<tr>
<td><form:input path="name" /></td>
</tr>
<tr>
<td>
<form:errors path="name*" />
</td>
</tr>
Note that there is a star at the end of the path value to indicate that all error messages for the name must be displayed.
As you can see, the problem is that, if there is no error message, there will be an extra row on the page that looks out of place to the user. The code above is an overly simplied version, so the actual code has a lot more stuff in it, which prevents me from moving the <form:errors> tag inside the tag containing the field.
Is there a way to find out if there is any message associated to a given path on the JSP level? Basically, I would like to do the following:
<c:if test="${what do I write here?}">
<tr>
<td>
<form:errors path="name*" />
</td>
</tr>
</c:if>
Thanks!
You can do something like this (notice that bind is from spring taglib):
<spring:bind path = "name*">
<c:if test="${status.error}">
<tr>
<td>
<form:errors path="name*" />
</td>
</tr>
</c:if>
</spring:bind>
I solved your problem by doing this:
<table>
<form:errors path="firstName">
<tr>
<td colspan="2">
<form:errors path="firstName"/>
</td>
</tr>
</form:errors>
<tr>
<td><form:label path="firstName"><spring:message code="helloworld.label.firstName"/></form:label></td>
<td><form:input path="firstName"/></td>
</tr>
</table>
errors tag body will be evaluated only if there are errors on the path.
The simplest answer is to not use tables for page layout. Utilizing div tags alleviates this problem altogether since divs are completely dimensionless if set to hidden.