Use object's method in a jstl page - java

I have a model with this method:
public List<String> getPriviledgeNames()
I'm trying to display a list of checkbox in my jstl page, and I'd like to checked only the ones which their name is in the list returned from my model.
So I have something like:
<li>
<input type="checkbox" name ="priviledge" id="CheckBox2" class="checkbox" value="clickthrough" />
<label for="CheckBox2">Clickthrough</label>
</li>
<li>
<input type="checkbox" name ="priviledge" id="CheckBox3" class="checkbox" value="details" />
<label for="CheckBox3">Details</label>
</li>
I'd like to add the checked="checked" only their name is in the list provided by my model's method. Is there a way to do this WITHOUT using scriptlet? I'd like to have no java code inside my pages...
Thanks for any helps!
Roberto

<c:when test = "${fn:contains(list,value)}">
-according to the docs it's actually doing a string/string comparison, so I assume it's actually checking whether the string value is a substring of list.toString().
You could also do a manual test on each value in the list with a forEach tag but that would be messier.

By using a map instead of a list could do something like this:
<c:if test="${yourModel.priviledgeNames['clickthrough'] ne null}">
checked="checked"</c:if>
Or just this: ${yourModel.priviledgeNames['clickthrough']} by mapping your checkbox name to checked="checked"

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 do I do a drop-down list without duplicate elements?

I have a list of objects and multiple drop-downs. I want to display the data from the list. But my problem is that I didn't want to have something like this:
For example: I don't want to have in drop-down a file name for two times :
file1
file1
file2
file3
file3
I want to have only: file1, file2, file3
This is my controller where I put the list in model
#GetMapping("/filter/functionality/misramessages")
public String filterFunctionality(Model model) {
model.addAttribute("misraMessages", misraMessagesService.findAllMisraMessagesFromDb());
return "functionality";
}
And after in html I do this:
<!-- Filter File Name-->
<div class="form-group row">
<label for="fileName" class="col-sm-2 col-form-label">File Name</label>
<div class="col-sm-10">
<select class="form-control" name="file_name" id="fileName">
<option th:value="0" text="Please Select"></option>
<option th:each = "misra : ${misraMessages}"
th:value="${misra.fileName}"
th:text="${misra.fileName}">
</option>
</select>
</div>
</div>
<!-- Filter Message Number-->
<div class="form-group row">
<label for="messageNumber" class="col-sm-2 col-form-label">Message Number</label>
<div class="col-sm-10">
<select class="form-control" name="message_number" id="messageNumber">
<option th:value="0" text="Please Select"></option>
<option th:each = "misra : ${misraMessages}"
th:value="${misra.messageNumber}"
th:text="${misra.messageNumber}">
</option>
</select>
</div>
</div>
.......
.......
Well I expect that misraMessagesService.findAllMisraMessagesFromDb() is returning list of String. So you can do something like this if you don't want to change your findAllMisraMessagesFromDb() method:
List<String> messages = misraMessagesService.findAllMisraMessagesFromDb();
Set<String> uniqueMsgs = new HashSet<String>(messages);
or you can also create a new method in misraMessagesRepository:
#Query("SELECT DISTINCT name FROM MisraMessages")
public List<MisraMessages> findDistinctMisraMessagesFromDb();
either of the two will work.
Never go for JAVA way to do the same because it is simply double processing time.
I would avoid processing in Java level code as it is easily possible by query level.
Just use Select distinct keyword and it works like a charm..!!
Keep it simple.
Its always better not to bring in duplicates to memory if that is causing issues and duplicate removal is needed.
So instead of using repository method - misraMessagesRepository.findAll(); , you need to write a new method in that repository which returns DISTINCT results and use that method in DAO.
#Query("SELECT DISTINCT * FROM MESSAGES_TABLE" , nativeQuery = true)
List<MisraMessages> findDistinctMessages();
You haven't shown your repository so I used dummy table name. Show your repository code and Entity details if still confused and need better answer.
Convert your List into Set. It will remove your duplicates then put into model.

How to display a Set property in a spring form?

I am working on a Spring MVC web app and I'm trying to figure out a way to display a property of type Set that is part of the entity in question. For the rest of the properties (String, boolean, int, etc) I can get away with the JSP file just using something like this to display them :
<li>
<label for="active">Active : </label>
<form:checkbox path="active" id="active" disabled="true"/>
<span><form:errors path="active" cssClass="error"/></span>
</li>
However, for a property of the entity which is a Set of other entities I cannot figure out how to display it. I'm thinking of using some sort of sub-table but I fiddled with it a lot with no success. I tried searching google and can't quite find what I need.
Thanks!
* New problem, but getting there! *
My OrderedMed class has a property of type StrengthUnit and I'm able to display its name using the method in the comments below :
<li>
<label for="meds[${loop.index}].strengthUnit.name">Strength Units : </label>
<form:input path="meds[${loop.index}].strengthUnit.name"/>
<form:errors path="meds[${loop.index}].strengthUnit.name" cssClass="error" />
</li>
However, I need this to be a drop-down that the user can change. My Med entity also has a property of type StrengthUnit and I'm able to accomplish what I want in its respective edit page by sending a list of all Strength Units from the controller and using the following code :
<select name="strengthUnit" path="strengthUnit.name" id="strengthUnit">
<option value="0" ${med.strengthUnit eq null ? 'selected' : ''}></option>
<c:forEach items="${strengthUnits}" var="strengthUnitSingle">
<option value="${strengthUnitSingle.id}" ${med.strengthUnit.name eq strengthUnitSingle.name ? 'selected' : ''}>${strengthUnitSingle.name}</option>
</c:forEach>
</select>
I'm trying to do the same thing with this entity and I cannot seem to make it work using the method suggested in the comments. I'm trying the below code :
<select name="strengthUnit" path="strengthUnit.name" id="strengthUnit">
<option value="0" ${meds[loop.index].strengthUnit eq null ? 'selected' : ''}></option>
<c:forEach items="${strengthUnits}" var="strengthUnitSingle">
<option value="${strengthUnitSingle.id}" ${meds[loop.index].strengthUnit.name eq strengthUnitSingle.name ? 'selected' : ''}>${strengthUnitSingle.name}</option>
</c:forEach>
</select>
Now i am getting this exception again :
javax.el.PropertyNotFoundException: Property '0' not found on type mdhis_webclient.entity.OrderedMed
I am using the same method to access the Set's index, what am I doing wrong?
Thanks!
You will probably need a forEach loop with the varStatus, example:
<c:forEach var="yourVar" items="${yourList}" varStatus="loop" >
<label for="yourVar[${loop.index}].something">Something ${loop.index + 1}</label>
<form:input path="yourVar[${loop.index}].someting" cssClass="form-control" autocomplete="off" />
<form:errors path="yourVar[${loop.index}].something" cssClass="text-danger" />
</c:forEach>
For the second part of my question, this is what i needed! I just needed a toString() method to my StrengthUnit entity (they should all have one anyway!)
<form:select name="strengthUnit" path="meds[${loop.index}].strengthUnit.name" id="strengthUnit">
<form:option value="0" label=""></form:option>
<form:options items="${strengthUnits}" />
</form:select>

can't reference iteration variable in Thymeleaf

I try to iterate a list of items using th:each,
<div class="row" th:each="item : *{items}">
<input type="text" th:field="item.name"/>
</div>
it works if I access the iteration variable using th:text, but throws
java.lang.IllegalStateException: Neither BindingResult nor plain
target object for bean name 'item' available as request attribute
when I use th:field to access it, where did I do wrong?
Something like this could work:
<div class="row" th:each="item, stat : *{items}">
<input type="text" th:field="*{items[__${stat.index}__].name}"/>
</div>
Take a peek here for more info: http://forum.thymeleaf.org/I-have-problem-in-binding-the-list-of-objects-contained-inside-a-object-on-the-form-using-thymeleaf-td3525038.html
th:field is broken in several ways, this is one of them.

value input field in foreach to input field outside foreach

The problem I have is best explained with a code example:
I have the following VIEW.jsp:
<c:forEach var="widget" items="${widgets}">
<div class="drag">
<p>Id: ${widget.id}</p>
<input class="editWidget" type="image" src="/tis/img/icons/edit.png" alt="Edit widget">
<input class="idWidget" type="hidden" value="${widget.id}">
</div>
</c:forEach>
<div id="editDialog" title="Edit widget">
<fieldset>
<input class="editWidgetId" type="hidden" value="??" id="editWidgetId">
</fieldset>
</div>
editWidgetId should have its 'value' attribute filled with the value of idWidget inside the foreach loop. This value should be different for each element in the loop (element is selected by edit button).
The questions:
How can I get the value of one input field to another input field?
How can I do this when a foreach loop is present?
Thanks in advance
Given you want dynamic behavior, this work has to be executed on the client-side by JavaScript as at the server-side, you have many widgets to one editDialog and are lacking the client-side user event to make your decision.
What you want to do is assign a function handler (or statement in my example below) to each editWidget to change the value of the editWidgetId input box with the appropriate value:
<input onclick="document.getElementById('editWidgetId').value = '${widget.id}'" class="editWidget" type="image" src="/tis/img/icons/edit.png" alt="Edit widget" >
Haven't tested this but I hope you get the idea

Categories