Thymeleaf issue with null and undefined

Many times I come across situations where I need to write a lot of extra code to get things to work without errors when a variable might be undefined.

In the example below, I have a form that I want to fill with populated values when they are available and leave the values blank when they are not. According to various Thymeleaf help sites (here and others), the following should work: ${user?.name} as you can see in the input below:

<input type="text" class="form-control" name="userName" id="userName" data-th-value="${user?.name}"/>

But it does not work, even when ā€œuserā€ is not null or undefined. Instead I have to make two versions of the form and then I get IntelliJ errors due to duplicate ids.

<input data-th-if="${user}" type="text" class="form-control" name="userName" id="userName" data-th-value="${user.name}"/>
<input data-th-if="${!user}" type="text" class="form-control" name="userName" id="userName" />

I hope there is a Thymeleaf setting somewhere that can enable this feature.

Would be nice if it worked.

Just to share, I usually do like this:

<div data-th-if="${user}" data-th-remove="tag">
  <input type="text" class="form-control" name="userName" id="userName" data-th-value="${user.name}"/>
</div>

That still leaves me duplicating most of the form, but if ${user?.name} worked then I wouldn’t have to. I want each input to render no matter what. That way I could use the same form to create a content, or edit an existing content.

True, misinterpreted the question.

Would be very useful to get ${user?.name} working. Especially for form handling.

I just set this up for a form I’m working on. On error I send the ā€œmessageā€ JSON full of info, and all the sent input fields as washed (ā€œsafeā€) strings back so I can populate the fields again (to assist user in correct their errors).

When testing this little Thymeleaf snippet I actually got this working, could it work for you?

<input type="text" name="company" id="input_company" aria-describedby="label_company" class="form-control" data-th-value="${not #lists.isEmpty(message.elements) ? message.elements.company : ''}" />

The magic that does it (checks if list is not empty (with Java) and fetches a value:

${not #lists.isEmpty(message.elements) ? message.elements.company : ''}"

data-th-value="${user ? user.name : ā€˜ā€™ }" should work for setting an empty value if the user is null.
If only user.name is null or undefined, you shouldn’t need any checks.

In my form application (beta will be released in a few days), I use this frequently.
Actually, I use this bit for (almost) any html5 input type (except e.g. radio buttons or selects, which have different markup):

<input data-th-type="${input.type}" type="text"
    data-th-id="${input.id}" id="input-id"
    data-th-name="${input.name}" name="input-name"
    data-th-value="${input.value}"
    data-th-readonly="${input.readonly}"
    data-th-disabled="${input.disabled}"
    data-th-size="${input.size}"
    data-th-maxlength="${input.maxlength}"
    data-th-autocomplete="${input.autocomplete}"
    data-th-autofocus="${input.autofocus}"
    data-th-formaction="${input.formaction}"
    data-th-formmethod="${input.formmethod}"
    data-th-formenctype="${input.formenctype}"
    data-th-height="${input.height}"
    data-th-width="${input.width}"
    data-th-min="${input.min}"
    data-th-max="${input.max}"
    data-th-step="${input.step}"
    data-th-list="${input.datalist ? input.datalist.id : ''}"
    data-th-multiple="${input.multiple}"
    data-th-pattern="${input.pattern}"
    data-th-placeholder="${input.placeholder}"
    data-th-required="${input.required}"
    data-th-checked="${input.checked}"
    data-th-class="${input.class}"
    data-th-title="${input.title}"
    data-th-accept="${input.accept}"
    th:attr="minlength=${input.minlength},capture=${input.capture}"/>

Most attributes are undefined for a single input type, but that is not relevant. However, for input.datalist.id, I do a check to see if input.datalist is defined.

2 Likes

I do not think this will work in Thymeleaf. Thymeleaf (as we uses it) uses OGNL under the hoods and it does not support ? in the way you want. See https://commons.apache.org/proper/commons-ognl/language-guide.html for reference on OGNL.

What about the approach mentioned by @it_vegard above?

data-th-value="${user ? user.name : '' }"

The same URL contains the following line under the heading ā€œVariable referencesā€:

listeners.size().(#this > 100? 2*#this : 20+#this)

Which seems like something similar to the approach I use, though I don’t know the #-syntax.
I can do some more testing, but I haven’t had any problems with this yet.

Thanks. That works just fine. I thought I had tried it that way before, but who knows, I probably had a typo or something.

1 Like