smsnheck
smsnheck

Reputation: 1593

Binding embedded List of objects on a Thymeleaf template for a POST request

I am developing a grocery store list web application. One feature should be (un)checking found/bought items on the list. Displaying all the values works fine. But when I check some checkboxes on some bought items and try to POST it afterwards the incomming @ModelAttribute in the spring MVC controller is null (except the id).

I hope you can help me.

Here are my classes:

public class PurchaseList {

private Long id;
private List<PurchaseItem> purchaseItemList;
private DateTime purchaseDate;
private boolean done;
}


public class PurchaseItem {

private Long id;
private String purchaseItemName;
private PurchaseCategory purchaseCategory;
private PurchaseList purchaseList;
private boolean found;
}

The Controller:

@RequestMapping(value="/{id}", method=RequestMethod.POST)  
public String postPurchaseList(@PathVariable(value="id") Long id, @ModelAttribute("purchaseList") PurchaseList purchaseList, Model model) {
  List<PurchaseList> notDonePurchaseList = purchaseListService.getNotDonePurchaseList();
  model.addAttribute("notDonePurchases", notDonePurchaseList);
  purchaseListService.savePurchaseList(purchaseList);
  return "purchaseList";
}

The Thymeleaf template

<form action="#" th:action="@{/purchaseList/{purchaseListId}/(purchaseListId=${purchaseList.id})}" th:object="${purchaseList}" method="post">
      <table class="table table-bordered table-hover">
        <thead>
          <tr>
            <td>Found</td>
            <td>Item</td>
            <td>Category</td>
          </tr>
        </thead>
        <tr th:each="item,status : ${purchaseList.purchaseItemList}">
          <td><input type="checkbox" th:checked="${item.found}" th:value="*{purchaseItemList[__${status.index}__].found}" /></td>
          <td th:text="${item.purchaseItemName}"></td>
          <td th:text="${item.purchaseCategory.categoryName}"></td>
        </tr>
      </table>
      <input type="submit" value="Submit" id="submit" />
      </form>

I know that I doesn't set the other values (only the found property). Or is this the problem?

Best regards

Edit:

  1. Initialized as suggested the ArrayList purchaseItemList. Now an empty ArrayList is returned to the controller.

Upvotes: 0

Views: 4009

Answers (2)

Biswajit Debnath
Biswajit Debnath

Reputation: 43

Initialize the purchaseItemList in PurchaseList class. public class PurchaseList { private Long id; private List<PurchaseItem> purchaseItemList=new ArrayList<>(); private DateTime purchaseDate; private boolean done; }

Give a input field an id like this.

<td><input type="checkbox" th:checked="${item.found}" th:value="* {purchaseItemList[__${status.index}__].found}" th:id='purchaseList.purchaseItemList[__${status.index}__].found'/></td>

Upvotes: 0

smsnheck
smsnheck

Reputation: 1593

I've found the problem and the solution.

I've seen in some tutorials and blog posts the usage of th:field=*{..} but I didn't use it, because i trusted the Spring Tool Suite (it doesn't offer the th:field attribute on autocomplete. Therefore I was sure that this attribute couldn't be used anymore. But I was wrong. I changed in my template code some of the *th:value=${..} attributes to th:field=*{..} as follows:

<form action="#" th:action="@{/purchaseList/{purchaseListId}/(purchaseListId=${purchaseList.id})}" th:object="${purchaseList}" method="post">
  <input type="hidden" th:field="*{id}" />
  <input type="hidden" th:field="*{purchaseDate}" />
  <input type="hidden" th:field="*{done}" />
  <table class="table table-bordered table-hover">
    <thead>
      <tr>
        <td>Found</td>
        <td>Item</td>
        <td>Category</td>
      </tr>
    </thead>
    <tr th:each="item,status : ${purchaseList.purchaseItemList}">
      <td><input type="checkbox" th:checked="${item.found}" th:field="*{purchaseItemList[__${status.index}__].found}" th:id="${'purchaseList.purchaseItemList[__${status.index}__].found' + 'status.index'}"/></td>
      <td th:text="${purchaseList.purchaseItemList[__${status.index}__].purchaseItemName}">
        <input type="hidden" th:field="*{purchaseItemList[__${status.index}__].purchaseItemName}" 
        th:value="${purchaseList.purchaseItemList[__${status.index}__].purchaseItemName}"
        th:id="${'purchaseList.purchaseItemList[__${status.index}__].purchaseItemName'}"
        />
      </td>
      <td th:text="${item.purchaseCategory.categoryName}">
        <input type="hidden" th:field="*{purchaseItemList[__${status.index}__].purchaseCategory.categoryName}" 
        th:value="${purchaseList.purchaseItemList[__${status.index}__].purchaseCategory.categoryName}"
        th:id="${'purchaseList.purchaseItemList[__${status.index}__].purchaseCategory.categoryName'}"
        />
      </td>
    </tr>
  </table>
  <input type="submit" value="Submit" id="submit" />
  </form> 

Now it works better. I get the "found" attributes in the controller. The other values are not set. But I think I messed up something within the hidden input fields.

Upvotes: 0

Related Questions