Spel Collection Selection

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view

Spel Collection Selection

Can anyone point me to why this spel expression will not parse in the th:attr tag in my option tag?

I have an outer loop that loops over a list of roles, an inner loop that draws a select and the form bean has a collection of elements that have both the user and the role.  I want to write selected=selected if the current role in the role loop && the current user in the user loop matches one of the elements in the collection from the form bean

Gisted the code to make it easier


We're porting from PLAY! Framework where we had groovy and there I would do

formBean?.membershipList.find{it.user.id == u.id && it.userRole.id == role.id}

Trying to do the same in SpEL

Reply | Threaded
Open this post in threaded view

Re: Spel Collection Selection


the expression
      < div th:each={role : ${roles} >

should be
      < div th:each="role : ${roles}">

There are some mistakes in the expression
     th:attr="selected=${formBean.membershipList.?[user.id == user.id AND userAssetRole.id == role.id]} ? 'selected'"

1.- Should be ?. insteadof .?
2.- user.id == user.id is always true
3.- The code inside [...] returns a boolean, but it should return an int (list index)

Anyway, I recommend you to move this logic to Java code, as in

Reply | Threaded
Open this post in threaded view

Re: Spel Collection Selection

In reply to this post by dstarh
I will add a couple of things to Zemi's answer, if I may:

I understand from the groovy equivalent that at this Spring EL expression:

    formBean.membershipList.?[user.id == user.id AND userAssetRole.id == role.id]

You are trying to filter members from a collection (".?" therefore is correct), but your filtering looks strange to me. Inside a filtering expression you must use the "#this" placeholder to refer to the item being iterated (equivalent to groovy's "it"), so your expression maybe should look more like:

    formBean.membershipList.?[#this.user.id == user.id AND #this.userRole.id == role.id]

...or something like that. In any case, it is a Spring EL syntax issue and I don't know exactly what you are trying to filter.

Nevertheless, leaving Spring EL syntax apart. The thymeleaf parts:

If your expression returns a list, even if this is an empty collection, it will evaluate as "true" (which mimics the standard SpringEL behaviour: a non-null object which is not a String, not a boolean and not a number is true).

So you probably want to add an ".isEmpty()" to the end of your collection evaluating expression.

Besides, note that there is a "th:selected" attribute in Thymeleaf that allows you to specify a boolean expression inside, and that will precisely do what you need: output "selected="selected"" if the expression evaluates to true, and output nothing if it evaluates to false.

As  a suggestion, I would also add a "th:object" at the form tag to select your "formBean" object for *{...} expresions. So your code will probably look better like:

    <form ... th:object="${formBean}">
        <div th:each="role : ${roles}">
            <option th:each="user : ${users}"
                       th:selected="*{membershipList.?[#this.user.id == user.id AND #this.userRole.id == role.id}"
                       th:text="${user.firstName} + ' ' + ${user.lastName}">John Smith</option>

Hope this helps.