Spel Collection Selection

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

Spel Collection Selection

dstarh
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

https://gist.github.com/3759568

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

Zemi
Administrator
Hello,

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
     ${formBean.getMemberShipFor(role)}


Reply | Threaded
Open this post in threaded view
|

Re: Spel Collection Selection

danielfernandez
Administrator
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}">
          <select>
            <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>
          </select>
        </div>
        ...
    </form>


Hope this helps.


Regards,
Daniel.