Submit Map<String,Integer> Thymeleaf - java

Model has Map(String,Integer), this map displayed on page in checkboxes like:
<ul>
<li th:each="item : ${map}">
<input type="checkbox" th:checked="${item.value} == 1" th:id="${item.key}"/>
<label th:for="${item.key}" th:text="${item.key}"/>
</li>
</ul>
How should i submit checkboxes state changes?

If you are using Spring MVC as your application and Thymeleaf as your view engine please check out this section on dynamic forms and working with them:
http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dynamic-fields
Essentially what you want to do is have an object that would have a Map as a variable within it, which would then bind all your inputs against when it hits the controller.
e.g.
public class MyObject {
Map<String, Integer> myMap;
// getters and setters
}

Related

Accesssing model attribute in JPA doesn't work

I am having problems accessing a model attribute in my controller, using Spring.
When adding to the model, I write the status code as a key and the enumeration name as a value. The status code is e.g. AVAILABLE, NOTAVAILABLE, etc.:
String code = status.getCode();
String enumerationName = enumerationService.getEnumerationName(status, currentLocale);
model.addAttribute(code, enumerationName);
On my JPA page, I am trying to access the corresponding value using the key (status code, e.g. AVAILABLE):
<div data-availability>
<c:forEach items="${StockLevelDeliveryStatus.values()}" var="status">
<c:set var="textStyle" value="text-success" />
<c:if test="${status.code.toLowerCase() == 'notavailable'}">
<c:set var="textStyle" value="" />
</c:if>
<div class="d-none display-22 pb-2 ${textStyle}" data-availability-item data-${status.code.toLowerCase()}>
${status}
</div>
</c:forEach>
</div>
For example, the value of status is AVAILABLE and this is what is output in ${status}. However, I want the value AVAILABLE to be used as a key to return me the correct value that I set in the model above. If I change the ${status} statement to, say, ${AVAILABLE} instead, which is the concrete key, the appropriate value from the model is returned:
<div class="d-none display-22 pb-2 ${textStyle}" data-availability-item data-${status.code.toLowerCase()}>
${AVAILABLE}
</div>
If I understand it correctly, then instead of passing the enum value as a key, I need to somehow teach Spring to search in the model for the appropriate key.
As recommended in one of the replies, I also tried writing the Map<StockLevelDeliveryStatus, String> directly into the model:
Map<StockLevelDeliveryStatus, String> statusMap = new HashMap<StockLevelDeliveryStatus, String>();
for (StockLevelDeliveryStatus status : StockLevelDeliveryStatus.values()) {
statusMap.put(status, enumerationService.getEnumerationName(status, currentLocale));
}
model.addAttribute("statusMap", statusMap);
And the JSP accordingly:
<div data-availability>
<c:forEach items="${StockLevelDeliveryStatus.values()}" var="status">
<c:set var="textStyle" value="text-success" />
<c:if test="${status.code.toLowerCase() == 'notavailable'}">
<c:set var="textStyle" value="" />
</c:if>
<div class="d-none display-22 pb-2 ${textStyle}" data-availability-item data-${status.code.toLowerCase()}>
${statusMap[status]}
</div>
</c:forEach>
</div>
Here it already fails when accessing the model, because with this approach I do not get any output on the JSP.
Does anyone have any ideas on how to make this work?
Why not simply put a Map<StockLevelDeliveryStatus, String> into the model? You could then simply use ${statusMap[status]}.

How to pass a list from the view to the controller in Spring MVC with thymeleaf?

I have an html page to edit a list of persons.
When the page is opened the controller gets the list of persons from the db and binds to the view.
That works fine.
Then the user edits the data and clicks save.
Now I need to submit the edited data of each person to the controller so that the controller can save the edits.
I'm trying to do that using #ModelAttribute ArrayList<Person> as shown below but it's not working.
The arraylist comes empty.
How do I do for the arraylist to come filled with all of the persons objects from the form?
View
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<form action="editperson" method="post">
<th:block th:each="person : ${personBind}">
Name:
<input type="text" th:value="${person.name}" />
</br></br>
Age:
<input type="text" th:value="${person.age}" />
</br></br>
</th:block>
</br></br>
<input type="submit" name="btnSaveEdit" value="Save"/>
</form>
Controller
#RequestMapping(value = "/editperson", params = "btnSaveEdit", method = RequestMethod.POST)
public String saveEditPerson(#ModelAttribute ArrayList<Person> personsList){
//save edit code here
return "editperson";
}
Spring MVC with Thymeleaf does indeed use model attributes to store data for the Thymeleaf pages. This guide shows how to load data from a form into the application. Try wrapping the ArrayList inside of a custom object and access the list via that object as a ModelAttribute rather than working with an ArrayList directly.
The saveEditPerson method should probably be named "saveEditPersons" since you are parsing a list of persons rather than just one.

Spring Boot & Thymeleaf: list of links

Java/Spring Boot web app here using Thymeleaf as the templating engine.
My bean:
public class InventoryItem {
private String modelNumber;
private String name;
// getters, setters and ctors omitted for brevity
}
My Spring controller:
#Controller
#RequestMapping("/inventory")
public class InventoryController {
#GetMapping("/{inventoryId}")
public String viewInventory(#PathVariable("inventoryId") String inventoryId, Model model) {
List<InventoryItem> inventory = getSomehow(inventoryId);
model.addAttribute("inventory", inventory);
return "inventory";
}
}
And a snippet from the inventory.html file that Thymeleaf must template:
<div class="col-md-4 mt-5">
<div class="panel-body">Inventory Items</div>
<ul>
<li th:each="item :${inventory}" th:text="${item.name}"></li>
</ul>
</div>
At runtime this produces a nice unordered list of inventory item names.
What I want now is to make this an unordered list of hyperlinks (<a/>) such that the rendered HTML looks like so:
<ul>
<li>Goose</li>
<li>Duck</li>
<!-- etc. -->
</ul>
Where 12345 and 23456 are InventoryItem#modelNumbers and where Goose and Duck are InventoryItem#names. I've asked the Google Gods high and low and cannot find a working example of using Thymeleaf to render a list (ordered/unordered alike) of hyperlinks. Any ideas?
Something like this would work ...
<div class="col-md-4 mt-5">
<div class="panel-body">Inventory Items</div>
<ul>
<li th:each="item :${inventory}">
<a th:href="#{/inventoryDetails/{modelNumber}(modelNumber=${item.modelNumber})}" th:text="${item.name}">Goose</a>
</li>
</ul>
</div>
If you would like to get more information on how to work with Link URLs, follow Thymeleaf documentation.

Share data via thymeleaf fragment

I have a thymeleaf fragment called nav which I include in all front-end pages, it goes like so:
<nav class="navbar navbar-expand-md navbar-dark bg-dark" th:fragment="nav">
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
How to get Java data here ?
</ul>
</div>
</nav>
But what I want to do now is get some data from the database and have that data available in this fragment, which in turn will appear on every page that includes this fragment.
If I want to pass data to a view regularly from a controller, I would use Model and model.addAttribute and return the appropriate view which would contain the relevant model data, but how can I pass data to this fragment?
You can create an interceptor and add model attribute on the postHandle method (which allows you access to the ModelAndView object. The interceptor will have to be on all the controllers that have this fragment.
You can add the relevant model attributes to the session and access them via ${session.attribute}.
Use the #ControllerAdvice annotation in combination with #ModelAttribute to add a model attribute to all controllers.

Inconsistent Expression Language behaviour, same expression different values

The same EL expression ${taskId} gives two different values in different places.
I am using the Stripes framework, along with MongoDB and Morphia for Object-Mapping (and of course Java/JSP/etc).
Using the following JSP/Expression Language code:
<c:forEach items="${actionBean.tasks}" var="listTask">
<c:set var="taskId" scope="page" value="${listTask.id}"/>
<s:form method="post" beanclass="action.TaskActionBean">
${taskId}<s:hidden name="task.id" value="${taskId}"/>
<s:submit name="promoteTask" value="Up" />
</s:form>
</c:forEach>
Gives the following generated code:
<form method="post" action="/scrumyogi/">
4ef99b730364de7ec70dbd68
<input type="hidden" value="4ef99b6c0364de7ec70dbd67" name="task.id">
<input type="submit" value="Up" name="promoteTask">
<div style="display: none;">
<input type="hidden" value="NPNEJw6tUWfRBXf-vVOLTw==" name="_sourcePage">
<input type="hidden" value="XbfUDiSHGrU=" name="__fp">
</div>
</form>
As you can see ${taskId} is printing out 4ef99b730364de7ec70dbd68 and then 4ef99b6c0364de7ec70dbd67, which makes no sense to me, I need ${taskId} to print out the same value 4ef99b730364de7ec70dbd68 is the correct one.
Is there some known issue that could cause this.
EDIT: the real problem is that the ${taskId} within the hidden form tag is incorrect, I printed the other value to see what the expression contains, and then found that it's different in the different locations - which make things seriously confusing.
ActionBean code:
#UrlBinding("/")
public class TaskActionBean extends BaseActionBean{
String taskId;
Task task = new Task();
List<Task> tasks;
public final static String DISPLAY = "/index.jsp";
#DefaultHandler
public Resolution listTasks(){
tasks = Dao.datastore().find(Task.class).order("rank").asList();
return new ForwardResolution(DISPLAY);
}
public Resolution promoteTask(){
task.promoteTask();
tasks = Dao.datastore().find(Task.class).order("rank").asList();
return new ForwardResolution(DISPLAY);
}
// ... getters and setters
You have a taskId field in you action bean, and according to stripes taglib documentation:
The hidden tag assigns the value attribute by scanning in the following order:
for one or more values with the same name in the HttpServletRequest
for a field on the ActionBean with the same name (if a bean instance is present)
by collapsing the body content to a String, if a body is present
referring to the result of the EL expression contained in the value attribute of the tag.
So it probably finds the field in your action bean and takes the value from there.
The other (jsp el) ${taskId} is assigned from task list element.
Change the taskId to some name that doesn't coincide with your action bean field and it should work.

Categories