0

There are Three classes

public Class Port{

private String portname;
// with getters and setters
}

public Class Application{
private String appName;
private List<Port> ports=  new ArrayList<Port>();
//  with getters and setters
}

public Class Service{
private String serviceName;
private List<Application> apps=  new ArrayList<Application>();
//  with getters and setters
}

Below snippet is part of the Thymeleaf HTML code to iterate through the fields.

<form action="#" th:action="@{/processWrapper}" th:object="${service}" method="post">
<table>
<div th:each="app, stat : *{apps}">
<tr>                   
<td><input type="text" th:field="*{apps[__${stat.index}__].appName}" th:name="|apps[${stat.index}]|" /></td>
<div th:each="port, stat1 : *{app.ports}">
<td><input type="text" th:field="*{app.ports[__${stat1.index}__].portname}" th:name="|app.ports[${stat1.index}]|" /></td>
    </div>
    </div></table></form>

Why is it not working?I get the error message:

Property or field 'ports' cannot be found on object of type 'service' maybe not public?

2
  • Does Service have a property called ports? Secondly, you typically make public and class lower case. Commented Apr 23, 2017 at 19:58
  • Service doesnt have ports. Service only has Arraylist of Application which inturn has array list of ports. The code has correct case. I have updated the above as well Commented Apr 23, 2017 at 20:36

1 Answer 1

4

Your html should look like this:

<form action="#" th:action="@{/processWrapper}" th:object="${service}" method="post">
    <table>
        <tr th:each="app, stat : *{apps}">                   
            <td><input type="text" th:field="*{apps[__${stat.index}__].appName}" /></td>
            <td th:each="port, stat1 : ${app.ports}"><input type="text" th:field="*{apps[__${stat.index}__].ports[__${stat1.index}__].portname}" /></td>
        </tr>
    </table>
</form>

As for what was wrong...

  1. You don't need all those extra divs. Just do the th:each on the trs and tds themselves.
  2. You don't need th:name when you use th:field. th:field generates the name property.
  3. This expression is invalid: *{app.ports[__${stat1.index}__].portname}.
    • First, you can't use *{} expressions on local variables. *{app} is invalid -- it's trying to resolve to ${service.app} which doesn't exist.
    • Second when you are building a th:field expressions, you have to build the entire path. The corrected expression is *{apps[__${stat.index}__].ports[__${stat1.index}__].portname}, which includes the entire path to portname.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.