Thymeleaf dynamically create forms using th:each

◇◆丶佛笑我妖孽 提交于 2021-01-27 23:18:36

问题


I would like to know how to create forms that uses th:object for each object looped in a th:each. For example, I have the following code.

HTML

<th:block th:each="store: ${stores}">
    <form th:object="${store}" th:action="@{/modify-store}">
        <input th:field="*{idStorePk}"/>
        <input th:field="*{name}"/>
        <input th:field="*{phoneNumber}"/>
        <button type="submit">Modify</button>
    </form>
</th:block>

Controller

@RequestMapping(value = "/stores")
public String getIndex(Model model) {
    model.addAttribute("stores", storeService.getAllStores());
    return "store";
}

So, I would like to add a form for each object, but it seems that it is not possible and I get the following error.

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'store' available as request attribute

So, I decided to add a @ModelAttribute in my controller, but can't get to return the actual store.

@ModelAttribute("store")
public Store getStore(Store store) {
    return store;
}

With this approach all my forms have null values. I also tried to add a @PathVariable, but can't see to bind it using th:object. Is there a solution for this?


回答1:


So for anyone stuck at a similar problem. I find out a work around that might help you out. First, you can't use th:object, it simply won't cut it. Instead, do the following.

<th:block th:each="store: ${stores}">
    <form class="store-form" th:action="@{/modify-store}">
        <input th:name="idStorePk" th:value="${store.idStorePk}"/>
        <input th:name="name" th:value="${store.name}"/>
        <input th:name="phoneNumber" th:value="${store.phoneNumber}"/>
        <button class="submit-button" type="submit">Modify</button>
    </form>
</th:block>

Then just add something similar to the controller.

@PostMapping(value = "/modify-store")
@ResponseBody
public boolean deleteEntry(@ModelAttribute Store store) throws Exception {
    // Your code here...
    return true;
}

If you want to send it asynchronously then you will need to add some JS code in order for it to work. It should look something like the code below.

const forms = document.querySelectorAll('.store-form');
forms.forEach(form => {
   form.addEventListener('submit', event => {

   // Stop the normal form submit triggered by the submit button
   event.preventDefault();

   const formInputs = form.getElementsByTagName("input");
   let formData = new FormData();
   for (let input of formInputs) {
       formData.append(input.name, input.value);
   }

   fetch(form.action,
   {
        method: form.method,
        body: formData
   })
   .then(response => response.json())
   .then(data => console.log(data))
   .catch(error => console.log(error.message))
   .finally(() => console.log("Done"));
});



回答2:


You're sending stores in your controller in model-attribute and on your second controller where you're submitting your form you're using store that's the reason you're getting this error. So correct the spelling error on any one of your controller. Like this :-

@RequestMapping(value = "/stores")
public String getIndex(Model model) {
    model.addAttribute("stores", storeService.getAllStores());
    return "store";
}

And Your second controller where you're submitting your form will be like this -

@ModelAttribute("stores")
public Store getStore(Store store) {
    return store;
}


来源:https://stackoverflow.com/questions/54466032/thymeleaf-dynamically-create-forms-using-theach

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!