Утилита выражений Thymeleaf #lists.contains() не работает

Я работаю со стандартным диалектом тимелеафа и пытаюсь отобразить список флажков в форме. Рендеринг в порядке, однако проблема заключается в том, что я пытаюсь применить свойство «checked» к флажкам, используя служебный метод выражения тимелеафа #lists.contains().

Итак, у меня есть класс модели, который имеет следующие поля:

private List<Template> templates;

@FormParam("selectedTemplates")
private List<String> selectedTemplates = Lists.newArrayList();

HTML-фрагмент шаблона Thymeleaf:

<div th:each="template : *{templates}">
    <input type="checkbox" name="selectedTemplates" th:value="${template.id}" 
    th:checked="${#lists.contains(product.selectedTemplates, template.id)}" />
    <label th:text="${template.filename} + ' (' + ${template.description} + ')'" />
    <!-- Attempt to use the list contains to check the field -->
    <div th:text="${product.selectedTemplates}"/>
    <div th:text="${template.id}"/>  
    <div th:text="${#lists.contains(product.selectedTemplates, template.id)}" />
</div>

Вывод на странице для одного из флажков, который должен быть установлен.

<input type="checkbox" name="selectedTemplates" value="4" /> (Template Name)
<div>[4,5]</div>
<div>4</div>
<div>false<div>

Итак, как видите, я печатаю список со значениями [4,5] и использую метод #lists.contains, чтобы узнать, есть ли в нем template.id, однако этот метод всегда возвращает false. Я даже пробовал некоторые жестко закодированные идентификаторы, чтобы проверить метод, и всегда получаю «ложь».

Например:

<div th:text="${product.selectedTemplates}"/>
<div th:text="${#lists.contains(product.selectedTemplates, 4)}" />

Выводит [4,5]false

<div th:text="${product.selectedTemplates}"/>
<div th:text="${#lists.contains(product.selectedTemplates, '4')}" />

Выводит [4,5]false

Не уверен, что я делаю неправильно, но это кажется таким прямолинейным, не знаю, что еще попробовать. Я предполагаю, что что-то не так с синтаксисом. Любые предложения или советы приветствуются. Я не могу найти какие-либо ресурсы по устранению этой проблемы, руководство по тимелеафу быстро замалчивает этот раздел.


person Tom Lerma    schedule 18.12.2013    source источник


Ответы (4)


Я представил этот ответ на форуме тимелеафа и получил некоторую помощь в определении основной причины и решения. См. [http://forum.thymeleaf.org/Problem-with-thymeleaf-expression-utility-lists-contains-td4027317.html][1]

По сути, односимвольные строки интерпретируются как тип символа по умолчанию и поэтому никогда не совпадают ни с одной из строк в списке. Многосимвольные строки оцениваются как строковый тип, поэтому работают должным образом. Инкапсулируя искомое значение в кавычки с кодировкой html, синтаксический анализатор вынужден оценивать односимвольную строку как строковый тип, а не как тип char. Например:

<div th:text="${#lists.contains(testList, &quot;3&quot;)}"/>
<div th:text="${#lists.contains(testList, &quot;P&quot;)}"/>

Просто хотел опубликовать это на случай, если кого-то заинтересует основная причина и решение.

person Tom Lerma    schedule 05.08.2014

я знаю, что вопрос старый, но я публикую этот ответ, так что он может быть полезен другим пользователям, имеющим ту же проблему.

я не знаю, вы это или другой пользователь, но здесь я обнаружил, что мы должны добавить

'' + шаблон.id

so:

th:checked="${#lists.contains(product.selectedTemplates, '' + template.id)}" 

для меня это сработало! Спасибо

person SaganTheBest    schedule 11.07.2014

Я провел дополнительные эксперименты и обнаружил проблему, из-за которой служебный метод #lists.contains() не работает для строки с одним символом. Я хотел бы добавить, что я использую тимелеаф 2.0.19, но также пробовал 2.1.1.RELEASE с тем же результатом.

Я создал простой список в своей модели и добавил несколько значений:

@FormParam("testList") 
private List<String> testList = Lists.newArrayList(); 

testList.add("test1"); 
testList.add("test2"); 
testList.add("3"); 
testList.add("P"); 
testList.add("33");

Затем протестировали метод #lists.contains() следующим образом:

<div th:text="${product.testList}"/>
<div th:text="${#lists.contains(product.testList, 'test1')}"/>
<div th:text="${#lists.contains(product.testList, 'test2')}"/>
<div th:text="${#lists.contains(product.testList, '3')}"/>
<div th:text="${#lists.contains(product.testList, 'P')}"/>
<div th:text="${#lists.contains(product.testList, '33')}"/>

И вывод следующий:

<div>[test1, test2, 3, P, 33]</div>
<div>true</div>
<div>true</div>
<div>false</div>
<div>false</div>
<div>true</div>

Таким образом, очевидно, что этот метод не работает для односимвольных строк. Поскольку я работаю над новым проектом, я просто сбрасываю последовательности, управляющие этими идентификаторами, чтобы у меня не было ни одного идентификатора персонажа для работы. Это, конечно, не то решение, на которое я надеялся, но оно работает. Я также добавлю, что для того, чтобы метод работал в контексте моего вопроса, мне пришлось добавить пустой символ в свой идентификатор следующим образом:

th:checked="${#lists.contains(product.selectedTemplates, '' + template.id)}"

Без него метод contains вернул бы «false», потому что template.id имеет тип Long.

person Tom Lerma    schedule 19.12.2013
comment
Это довольно странно. Насколько я вижу в коде ListUtils, метод contains просто вызывает в целевом списке. В вашем случае это будет равно ${product.targetList.contains('3')}. Можете ли вы проверить, правильно ли это дает результат? В случае 3 я мог представить, что его внезапно обработают как int, и тогда список действительно не будет содержать его, но с «P», который должен возвращаться действительно верно. - person Martin Frey; 19.12.2013
comment
Или, что еще хуже, «P» рассматривается как символ. Не знаю, вернет ли это значение true, если список строк содержит - person Martin Frey; 19.12.2013
comment
Спасибо за отзыв, Мартин, я попробовал предложенный вами код: ${product.testList.contains('3')}, ${product.testList.contains('P')}, ${product.testList.contains(' 33')} И результаты были одинаковыми: ложь, ложь, истина, так что, возможно, это связано с тем, что он пытается неправильно определить тип и, следовательно, не работает с одним символом. - person Tom Lerma; 20.12.2013

Как я вижу, ваши selectedtemplates содержат список шаблонов, а не идентификаторы, верно?

Если это так, вы должны проверить список следующим образом:

<input type="checkbox" name="selectedTemplates" th:value="${template.id}" th:checked="${#lists.contains(product.selectedTemplates, template)}" />
person Martin Frey    schedule 19.12.2013
comment
List‹String› selectedTemplates — это только идентификатор, а не сущность шаблона. Я не думал идти по этому пути. Я нашел работу, которую я опубликую в ответе. - person Tom Lerma; 19.12.2013