Reputation: 2611
Having troubles getting values from dynamically added dropdown in thymeleaf.
This is my first
<select th:field="${offer.offerItemList[__${iterationStatus.index}__].mapa}" class="form-control input-sm ofa">
<option value="0" >---Choose option---</option>
<option th:each="attribute : ${offer.offerProductAttribute}" th:value="${attribute.id}" th:text="${attribute.name}"></option>
</select>
Based on selecton from this dropdown i am generating another dropdown with code similar to this :
var options = '<select th:field="offer.list" class="form-control input-sm"> <option th:value="0">--Choose--</option>';
$.each(value.offerProductAttributeValuesList, function (index, value) {
options += '<option th:value="' + value.id + '">' + value.value+ '</option>';
});
options+= '</select>';
of.closest('tr').find('td:last').html(options);
Dom elements generate fine. Everything is ok but values are never submitted with the rest of input fields.
I have done this many times but with previously rendered
<select>
dropdown on the server side, and i would just appendTo() options, but in this case i cannot do that since i potentially have more than 20 dropdowns, based on clients selection from previous dropdown.
I hope i am being clear enough about my issue.
Upvotes: 0
Views: 5963
Reputation: 2611
I am gonna answer my own question, since it took me quite some time to get around this problem, and my solution will probably help someone in the future.
The problem was : i had list of objects, and each one of those objects had another list of objects.
The problem is much easier to solve if you just render entire view from the backend (i was using thymeleaf). That way you can use thymeleaf expressions to map everything correctly Like this :
First you gonna need for each to iterate over top level list
<tr th:each="item,iterationStatus : ${offer.offerItemList}">
<select th:field="${offer.offerItemList[__${iterationStatus.index}__].mapa}">
This little piece of code __${iterationStatus.index}__
will basically use iteration index and you will end up with number for each iteration and rendered view will look like this offer.offerItemList[0].mapa
, and 1 and 2 and so on.
this way values will be mapped correctly, BUT, if you want to add fields dynamically things get a bit more complicated.
<div class="temp">
and write perfectly good jquery function something like this $('.temp').on('click',function(){ console.log("clicked")});
nothing will happen since jquery didnt bind your newly created element to any select/event listener. The solution is to use (document).$(document).on("click",".temp",function(){console.log('clicked');})
ok we have fixed front end issue, now newly created items work, but how do i tell spring to bind them to each object within list, which is part of another list? well you will have to use iteration index again :
var iteration = $(this).closest('tbody').find('td:first-child').find('input').attr('value');
ofc this is path to where i have placed hidden input field, you will have to tell jquery where to look according to your structure. var options = '<select name="offerItemList['+iteration+'].mapaValues">';
model.addAttribute("offer",offer);
object Offer has attribute, list of Products, so you would access that list with simple offer.productsList
, but each product has list of AttributeValues. So final setup looks like this
offer.products[0].attributes[0].name
products is an arrayList of objects of class Product, attributes is an arrayList of objects of class AttributeValues and name is a String. In order to let spring create object of class AttributeValues with information spring is receiving from dynamically(and non-dinamically) created forms from the frond-end, you will need to teach him how. If your new form with has input type="text" you are sending back String, so you will need to create a Custom constructor for
your class AttributeValues which will receive a String and which will tell Spring how to "construct" instance of that class with String. finally create two constructors, one default and one with String as a value :
public AttributeValues(){};
and another for String public AttributeValues(String n){this.name = n;};
Upvotes: 2
Reputation: 66
The problem you're most likely seeing here is that you're generating thymeleaf markup on the client-side. Thymeleaf is a server-side templating language, so the browser (and hence the Javascript) will only ever see plain HTML coming back.
Here's a few approaches to consider:
jQuery.get()
Upvotes: 1