input type=»checkbox» в Spring + Thymeleaf
Итак, для начала изменим в Thymeleaf-файле строку с input type=»checkbox» .
До:
Изменение в Controller:
th:checked имеет два значения: null и on , а это значит, что тип данных Boolean нам не подходит, а значит надо использовать String .
Вот как теперь выглядит GetMapping :
@GetMapping public ModelAndView getTest()
Вот как выглядит теперь PostMapping :
@PostMapping public ModelAndView postDeleteAccount( @ModelAttribute("confirm1") String confirm1, BindingResult bindingResult ) < ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("test"); if(!confirm1)< bindingResult .rejectValue("confirm1", "error.confirm1", "*You must confirm these conditions." ); >return modelAndView; >
P.S.
BindResult вроде НЕ работает с объектом String, потому что требуется Объект с конструктором. Данный пример является абстрактным и направлен на то, чтобы показать, работу с input type=»checkbox»
Check inputs with type checkbox with thymeleaf
I’ve been play around with spring-boot and thymeleaf; I’m trying to do a form where I will list numbers and the user will select them; however I would like to «checked» the third element (when equals 3) and I cannot see that the input is checked. I don’t have problems loading the information and display the checkboxes, the problem came when I want to check one of them by default when the page loads. I need some help identifying what it should be the issue or if it is a bug with th:checked property. I have this in the controller
@ModelAttribute("allFeatures") public List populateFeatures()
Руководство: Thymeleaf + Spring. Часть 2

2019-01-26 в 22:33, admin , рубрики: java, thymeleaf
5 Отображение Seed Starter Data
Первое, что покажет наша страница /WEB-INF/templates/seedstartermng.html, — это список с начальными стартовыми данными, которые в данный момент сохранены. Для этого нам потребуются некоторые внешние сообщения, а также некоторая работа выражений для атрибутов модели. Как это:
List of Seed Starters
Date Planted Covered Type Features Rows 13/01/2011 yes Wireframe Electric Heating, Turf 1 Thymus Thymi 12
Здесь много чего посмотреть. Давайте посмотрим на каждый фрагмент отдельно.
Прежде всего, этот раздел будет отображаться только при наличии seed стартеров. Мы достигаем этого с помощью атрибута th:never и функции #lists.isEmpty(. ).
Обратите внимание, что все служебные объекты, такие как #lists, доступны в выражениях Spring EL так же, как и в выражениях OGNL в стандартном диалекте.
Следующее, что нужно увидеть, это много интернационализированных (экстернализованных) текстов, таких как:
«>List of Seed Starters
Date Planted Covered Type Features Rows .
Это приложение Spring MVC, мы уже определили bean-компонент MessageSource в нашей конфигурации Spring (объекты MessageSource являются стандартным способом управления внешними текстами в Spring MVC):
@Bean public ResourceBundleMessageSource messageSource()
… и это свойство basename указывает, что в нашем пути к классам у нас будут файлы, такие как Messages_es.properties или Messages_en.properties. Давайте посмотрим на испанскую версию:
title.list=Lista de semilleros date.format=dd/MM/yyyy bool.true=sí bool.false=no seedstarter.datePlanted=Fecha de plantación seedstarter.covered=Cubierto seedstarter.type=Tipo seedstarter.features=Características seedstarter.rows=Filas seedstarter.type.WOOD=Madera seedstarter.type.PLASTIC=Plástico seedstarter.feature.SEEDSTARTER_SPECIFIC_SUBSTRATE=Sustrato específico para semilleros seedstarter.feature.FERTILIZER=Fertilizante seedstarter.feature.PH_CORRECTOR=Corrector de PH
В первом столбце таблицы мы покажем дату, когда был подготовлен стартер. Но мы покажем, что он отформатирован так, как мы определили в нашем DateFormatter. Для этого мы будем использовать синтаксис двойной скобки ($>), который будет автоматически применять сервис преобразования Spring, в том числе DateFormatter, который мы зарегистрировали при настройке.
13/01/2011
Далее показано, покрыт ли начальный контейнер seed starter или нет, путем преобразования значения свойства булевого покрытого бина в интернационализированное «да» или «нет» с буквальным выражением подстановки:
Теперь мы должны показать тип начального seed starter контейнера. Тип представляет собой java-перечисление с двумя значениями (WOOD и PLASTIC), и поэтому мы определили два свойства в нашем файле Messages с именами seedstarter.type.WOOD и seedstarter.type.PLASTIC.
Но чтобы получить интернационализированные имена типов, нам нужно добавить seedstarter.type. префикс к значению enum с помощью выражения, результат которого мы затем будем использовать в качестве ключа сообщения:
Wireframe
Самая сложная часть этого списка — колонка фич. В нем мы хотим отобразить все функции нашего контейнера, которые представлены в виде массива перечислений Feature, разделенных запятыми. Как «Электрическое отопление, газон».
- Подставьте соответствующий префикс ко всем элементам массива фич.
- Получите внешние сообщения, соответствующие всем ключам из шага 1.
- Присоедините все сообщения, полученные на шаге 2, используя запятую в качестве разделителя.
Для этого мы создаем следующий код:
Electric Heating, Turf
Последний столбец нашего списка на самом деле будет довольно простым. Даже если у него есть вложенная таблица для отображения содержимого каждой строки в контейнере:
1 Thymus Thymi 12
6 Создание Форм
6.1 Обработка командного объекта
Объект команды — это имя, которое Spring MVC дает бинам поддержки форм, то есть объектам, которые моделируют поля формы и предоставляют методы получения и установки, которые будут использоваться платформой для установления и получения значений, введенных пользователем в браузере.
Thymeleaf требует, чтобы вы указали объект команды, используя атрибут th:object в вашем теге :
Это согласуется с другим использованием th:object, но на самом деле этот конкретный сценарий добавляет некоторые ограничения для правильной интеграции с инфраструктурой Spring MVC:
- Значения атрибутов th:object в тегах формы должны быть выражениями переменных ($ ), указывающими только имя атрибута модели, без навигации по свойствам. Это означает, что выражение типа $ является допустимым, но $ не будет.
- Внутри тега другой атрибут th:object не может быть указан. Это согласуется с тем фактом, что HTML-формы не могут быть вложенными.
6.2 Inputs
Давайте теперь посмотрим, как добавить input в нашу форму:
Как видите, мы вводим новый атрибут: th:field. Это очень важная функция для интеграции Spring MVC, поскольку она выполняет всю тяжелую работу по связыванию вашего input со свойством в компоненте поддержки формы. Вы можете видеть его как эквивалент атрибута пути в теге из библиотеки тегов JSP Spring MVC.
Атрибут th:field ведет себя по-разному в зависимости от того, прикреплен ли он к тегу , или (а также в зависимости от конкретного типа тега ). В этом случае (input[type = text]) приведенная выше строка кода похожа на:
… Но на самом деле это немного больше, потому что th:field также будет применять зарегистрированную службу преобразования Spring, включая DateFormatter, который мы видели ранее (даже если выражение поля не заключено в квадратные скобки). Благодаря этому дата будет отображаться правильно отформатированной.
Значения для атрибутов th:field должны быть выражениями выбора (* ), что имеет смысл, учитывая тот факт, что они будут оцениваться на компоненте, поддерживающем форму, а не на переменных контекста (или атрибутах модели в жаргоне Spring MVC). ).
В отличие от выражений в th:object, эти выражения могут включать в себя навигацию по свойствам (фактически здесь позволено любое выражение, разрешенное для атрибута пути тега JSP).
Обратите внимание, что th:field также понимает новые типы элемента , представленные в HTML5, такие как , и т. д., эффективно добавляя полную поддержку HTML5 для Spring MVC.
6.3 Checkbox fields
th:field также позволяет определять входные данные checkbox флажков. Давайте посмотрим пример с нашей HTML-страницы:
" />
Обратите внимание, что здесь есть кое-что еще, кроме самого флажка, например, внешняя метка, а также использование функции #ids.next(‘closed’) для получения значения, которое будет применено к атрибуту id входных данных флажка.
Зачем нам нужно динамическое создание атрибута id для этого поля? Поскольку флажки являются потенциально многозначными, и, следовательно, к их значениям идентификатора всегда будет добавлен суффикс порядкового номера (внутренне используя функцию #ids.seq(…)), чтобы гарантировать, что каждый из флажков input одного и того же свойства имеет другое значение идентификатора.
Нам будет легче это увидеть, если мы посмотрим на такое многозначное поле флажка:
Обратите внимание, что на этот раз мы добавили атрибут th:value, потому что поле функций не является логическим, как было описано выше, а представляет собой массив значений.
Давайте посмотрим вывод HTML, сгенерированный этим кодом:
Здесь мы видим, как суффикс последовательности добавляется к каждому атрибуту id input и как функция #ids.prev(…) позволяет нам извлечь последнее значение последовательности, сгенерированное для определенного идентификатора ввода.
Не беспокойтесь об этих скрытых входах с name = «_ features»: они автоматически добавляются, чтобы избежать проблем с браузерами, не отправляющими невыбранные значения флажков на сервер при отправке формы.
Также обратите внимание, что если бы наше свойство features содержало некоторые выбранные значения в нашем form-backing bean, то th:field позаботилось бы об этом и добавило бы атрибут checked=«checked» в соответствующие входные теги.
6.4 Radio Button fields
Поля переключателей задаются аналогично не булевым (многозначным) флажкам, за исключением того, что, конечно, они не многозначны:
6.5 Dropdown/List selectors
Поля выбора состоят из двух частей: тега и его вложенных тегов . При создании поля такого типа только тег должен включать атрибут th:field, но атрибуты th:value во вложенных тегах будут очень важны, поскольку они будут обеспечивать возможность узнать, какова текущая выбранная опция (аналогично не булевым флажкам и переключателям).
Давайте перестроим поле типа выпадающий список:
На данный момент, понять этот кусок кода довольно легко. Просто обратите внимание, как приоритет атрибута позволяет нам устанавливать атрибут th:each в самом теге .
6.6 Dynamic fields
Благодаря расширенным возможностям связывания полей формы в Spring MVC, мы можем использовать сложные выражения Spring EL для привязки динамических полей формы к нашему form-backing bean. Это позволит нам создавать новые объекты Row в нашем компоненте SeedStarter и добавлять поля этих строк в нашу форму по запросу пользователя.
Для этого нам понадобится пара новых замапированных методов в нашем контроллере, которые добавят или удалят строку из нашего SeedStarter в зависимости от наличия определенных параметров запроса:
@RequestMapping(value="/seedstartermng", params=) public String addRow(final SeedStarter seedStarter, final BindingResult bindingResult) < seedStarter.getRows().add(new Row()); return "seedstartermng"; >@RequestMapping(value="/seedstartermng", params=) public String removeRow( final SeedStarter seedStarter, final BindingResult bindingResult, final HttpServletRequest req)
И теперь мы можем добавить динамическую таблицу в нашу форму:
Row Variety Seeds per cell 1 __].seedsPerCell>" />
Достаточно много вещей здесь, но не так много, чтобы не понимать… за исключением одной странной вещи:
Если вы помните из учебника «Использование Thymeleaf», то синтаксис __$__ является выражением предварительной обработки, которое является внутренним выражением, которое вычисляется до фактической оценки всего выражения. Но почему такой способ указания индекса строки? Не будет ли этого достаточно с:
…вообще-то нет. Проблема в том, что Spring EL не оценивает переменные в скобках индекса массива, поэтому при выполнении вышеприведенного выражения мы получим ошибку, сообщающую нам, что rows[rowStat.index] (вместо rows[0], rows[1] и т. д.) недопустимая позиция в коллекции строк. Вот почему здесь необходима предварительная обработка.
Давайте посмотрим на фрагмент полученного HTML-кода после того, как несколько раз нажали «Add Row»:
1 2
Soft, интернет, безопасность: новости, статьи, советы, работа
В 10-х годах я принимал участие в программе Европейского Союза Tempus «Освітні вимірювання, адаптовані до стандартів ЄС». В рамк.
Благодаря Интернету количество писателей и поэтов увеличивается в геометрической прогрессии. Поголовье читателей начинает заметно отставать.
понедельник, 28 января 2019 г.
Руководство: Thymeleaf + Spring. Часть 2 / Программирование на Java
5 Отображение Seed Starter Data
Первое, что покажет наша страница /WEB-INF/templates/seedstartermng.html, — это список с начальными стартовыми данными, которые в данный момент сохранены. Для этого нам потребуются некоторые внешние сообщения, а также некоторая работа выражений для атрибутов модели. Как это:
div class="seedstarterlist" th:unless="$"> h2 th:text="#">List of Seed Startersh2> table> thead> tr> th th:text="#">Date Plantedth> th th:text="#">Coveredth> th th:text="#">Typeth> th th:text="#">Featuresth> th th:text="#">Rowsth> tr> thead> tbody> tr th:each="sb : $"> td th:text="$>">13/01/2011td> td th:text="#<|bool.$|>" >yestd> td th:text="#<|seedstarter.type.$|>" >Wireframetd> td th:text="$<#strings.arrayJoin( #messages.arrayMsg( #strings.arrayPrepend(sb.features,'seedstarter.feature.')), ', ')>">Electric Heating, Turftd> td> table> tbody> tr th:each="row,rowStat : $"> td th:text="$">1td> td th:text="$">Thymus Thymitd> td th:text="$">12td> tr> tbody> table> td> tr> tbody> table> div>
Здесь много чего посмотреть. Давайте посмотрим на каждый фрагмент отдельно.
Прежде всего, этот раздел будет отображаться только при наличии seed стартеров. Мы достигаем этого с помощью атрибута th:never и функции #lists.isEmpty(. ).
div class="seedstarterlist" th:unless="$">
Обратите внимание, что все служебные объекты, такие как #lists, доступны в выражениях Spring EL так же, как и в выражениях OGNL в стандартном диалекте.
Следующее, что нужно увидеть, это много интернационализированных (экстернализованных) текстов, таких как:
«>List of Seed Starters
table> thead> tr> th th:text="#">Date Plantedth> th th:text="#">Coveredth> th th:text="#">Typeth> th th:text="#">Featuresth> th th:text="#">Rowsth> .
Это приложение Spring MVC, мы уже определили bean-компонент MessageSource в нашей конфигурации Spring (объекты MessageSource являются стандартным способом управления внешними текстами в Spring MVC):
@Bean public ResourceBundleMessageSource messageSource() < ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("Messages"); return messageSource; >
… и это свойство basename указывает, что в нашем пути к классам у нас будут файлы, такие как Messages_es.properties или Messages_en.properties. Давайте посмотрим на испанскую версию:
title.list=Lista de semilleros date.format=dd/MM/yyyy bool.true=sí bool.false=no seedstarter.datePlanted=Fecha de plantación seedstarter.covered=Cubierto seedstarter.type=Tipo seedstarter.features=Características seedstarter.rows=Filas seedstarter.type.WOOD=Madera seedstarter.type.PLASTIC=Plástico seedstarter.feature.SEEDSTARTER_SPECIFIC_SUBSTRATE=Sustrato específico para semilleros seedstarter.feature.FERTILIZER=Fertilizante seedstarter.feature.PH_CORRECTOR=Corrector de PH
В первом столбце таблицы мы покажем дату, когда был подготовлен стартер. Но мы покажем, что он отформатирован так, как мы определили в нашем DateFormatter. Для этого мы будем использовать синтаксис двойной скобки ($>), который будет автоматически применять сервис преобразования Spring, в том числе DateFormatter, который мы зарегистрировали при настройке.
td th:text="$>">13/01/2011td>
Далее показано, покрыт ли начальный контейнер seed starter или нет, путем преобразования значения свойства булевого покрытого бина в интернационализированное «да» или «нет» с буквальным выражением подстановки:
td th:text="#<|bool.$|>" >yestd>
Теперь мы должны показать тип начального seed starter контейнера. Тип представляет собой java-перечисление с двумя значениями (WOOD и PLASTIC), и поэтому мы определили два свойства в нашем файле Messages с именами seedstarter.type.WOOD и seedstarter.type.PLASTIC.
Но чтобы получить интернационализированные имена типов, нам нужно добавить seedstarter.type. префикс к значению enum с помощью выражения, результат которого мы затем будем использовать в качестве ключа сообщения:
td th:text="#<|seedstarter.type.$|>" >Wireframetd>
Самая сложная часть этого списка — колонка фич. В нем мы хотим отобразить все функции нашего контейнера, которые представлены в виде массива перечислений Feature, разделенных запятыми. Как «Электрическое отопление, газон».
Обратите внимание, что это особенно сложно, потому что эти значения перечисления также должны быть выведены, как мы делали с Types. Поток вывода следующий:
- Подставьте соответствующий префикс ко всем элементам массива фич.
- Получите внешние сообщения, соответствующие всем ключам из шага 1.
- Присоедините все сообщения, полученные на шаге 2, используя запятую в качестве разделителя.
Для этого мы создаем следующий код:
td th:text="$<#strings.arrayJoin( #messages.arrayMsg( #strings.arrayPrepend(sb.features,'seedstarter.feature.')), ', ')>">Electric Heating, Turftd>
Последний столбец нашего списка на самом деле будет довольно простым. Даже если у него есть вложенная таблица для отображения содержимого каждой строки в контейнере:
td> table> tbody> tr th:each="row,rowStat : $"> td th:text="$">1td> td th:text="$">Thymus Thymitd> td th:text="$">12td> tr> tbody> table> td>
6 Создание Форм
6.1 Обработка командного объекта
Объект команды — это имя, которое Spring MVC дает бинам поддержки форм, то есть объектам, которые моделируют поля формы и предоставляют методы получения и установки, которые будут использоваться платформой для установления и получения значений, введенных пользователем в браузере.
Thymeleaf требует, чтобы вы указали объект команды, используя атрибут th:object в вашем теге :
form action="#" th:action="@" th:object="$" method="post"> . form>
Это согласуется с другим использованием th:object, но на самом деле этот конкретный сценарий добавляет некоторые ограничения для правильной интеграции с инфраструктурой Spring MVC:
- Значения атрибутов th:object в тегах формы должны быть выражениями переменных ($ ), указывающими только имя атрибута модели, без навигации по свойствам. Это означает, что выражение типа $ является допустимым, но $ не будет.
- Внутри тега другой атрибут th:object не может быть указан. Это согласуется с тем фактом, что HTML-формы не могут быть вложенными.
6.2 Inputs
Давайте теперь посмотрим, как добавить input в нашу форму:
input type="text" th:field="*" />
Как видите, мы вводим новый атрибут: th:field. Это очень важная функция для интеграции Spring MVC, поскольку она выполняет всю тяжелую работу по связыванию вашего input со свойством в компоненте поддержки формы. Вы можете видеть его как эквивалент атрибута пути в теге из библиотеки тегов JSP Spring MVC.
Атрибут th:field ведет себя по-разному в зависимости от того, прикреплен ли он к тегу , или (а также в зависимости от конкретного типа тега ). В этом случае (input[type = text]) приведенная выше строка кода похожа на:
input type="text" id="datePlanted" name="datePlanted" th:value="*" />
… Но на самом деле это немного больше, потому что th:field также будет применять зарегистрированную службу преобразования Spring, включая DateFormatter, который мы видели ранее (даже если выражение поля не заключено в квадратные скобки). Благодаря этому дата будет отображаться правильно отформатированной.
Значения для атрибутов th:field должны быть выражениями выбора (* ), что имеет смысл, учитывая тот факт, что они будут оцениваться на компоненте, поддерживающем форму, а не на переменных контекста (или атрибутах модели в жаргоне Spring MVC). ).
В отличие от выражений в th:object, эти выражения могут включать в себя навигацию по свойствам (фактически здесь позволено любое выражение, разрешенное для атрибута пути тега JSP).
Обратите внимание, что th:field также понимает новые типы элемента , представленные в HTML5, такие как , и т. д., эффективно добавляя полную поддержку HTML5 для Spring MVC.
6.3 Checkbox fields
th:field также позволяет определять входные данные checkbox флажков. Давайте посмотрим пример с нашей HTML-страницы:
div> label th:for="$" th:text="#">Coveredlabel> input type="checkbox" th:field="*" /> div>
Обратите внимание, что здесь есть кое-что еще, кроме самого флажка, например, внешняя метка, а также использование функции #ids.next(‘closed’) для получения значения, которое будет применено к атрибуту id входных данных флажка.
Зачем нам нужно динамическое создание атрибута id для этого поля? Поскольку флажки являются потенциально многозначными, и, следовательно, к их значениям идентификатора всегда будет добавлен суффикс порядкового номера (внутренне используя функцию #ids.seq(…)), чтобы гарантировать, что каждый из флажков input одного и того же свойства имеет другое значение идентификатора.
Нам будет легче это увидеть, если мы посмотрим на такое многозначное поле флажка:
ul> li th:each="feat : $"> input type="checkbox" th:field="*" th:value="$" /> label th:for="$" th:text="#>">Heatinglabel> li> ul>
Обратите внимание, что на этот раз мы добавили атрибут th:value, потому что поле функций не является логическим, как было описано выше, а представляет собой массив значений.
Давайте посмотрим вывод HTML, сгенерированный этим кодом:
ul> li> input id="features1" name="features" type="checkbox" value="SEEDSTARTER_SPECIFIC_SUBSTRATE" /> input name="_features" type="hidden" value="on" /> label for="features1">Seed starter-specific substratelabel> li> li> input id="features2" name="features" type="checkbox" value="FERTILIZER" /> input name="_features" type="hidden" value="on" /> label for="features2">Fertilizer usedlabel> li> li> input id="features3" name="features" type="checkbox" value="PH_CORRECTOR" /> input name="_features" type="hidden" value="on" /> label for="features3">PH Corrector usedlabel> li> ul>
Здесь мы видим, как суффикс последовательности добавляется к каждому атрибуту id input и как функция #ids.prev(…) позволяет нам извлечь последнее значение последовательности, сгенерированное для определенного идентификатора ввода.
Не беспокойтесь об этих скрытых входах с name = «_ features»: они автоматически добавляются, чтобы избежать проблем с браузерами, не отправляющими невыбранные значения флажков на сервер при отправке формы.
Также обратите внимание, что если бы наше свойство features содержало некоторые выбранные значения в нашем form-backing bean, то th:field позаботилось бы об этом и добавило бы атрибут checked=«checked» в соответствующие входные теги.
6.4 Radio Button fields
Поля переключателей задаются аналогично не булевым (многозначным) флажкам, за исключением того, что, конечно, они не многозначны:
ul> li th:each="ty : $"> input type="radio" th:field="*" th:value="$" /> label th:for="$" th:text="#>">Wireframelabel> li> ul>
6.5 Dropdown/List selectors
Поля выбора состоят из двух частей: тега и его вложенных тегов . При создании поля такого типа только тег должен включать атрибут th:field, но атрибуты th:value во вложенных тегах будут очень важны, поскольку они будут обеспечивать возможность узнать, какова текущая выбранная опция (аналогично не булевым флажкам и переключателям).
Давайте перестроим поле типа выпадающий список:
select th:field="*"> option th:each="type : $" th:value="$" th:text="#>">Wireframeoption> select>
На данный момент, понять этот кусок кода довольно легко. Просто обратите внимание, как приоритет атрибута позволяет нам устанавливать атрибут th:each в самом теге .
6.6 Dynamic fields
Благодаря расширенным возможностям связывания полей формы в Spring MVC, мы можем использовать сложные выражения Spring EL для привязки динамических полей формы к нашему form-backing bean. Это позволит нам создавать новые объекты Row в нашем компоненте SeedStarter и добавлять поля этих строк в нашу форму по запросу пользователя.
Для этого нам понадобится пара новых замапированных методов в нашем контроллере, которые добавят или удалят строку из нашего SeedStarter в зависимости от наличия определенных параметров запроса:
@RequestMapping(value="/seedstartermng", params="addRow">) public String addRow(final SeedStarter seedStarter, final BindingResult bindingResult) < seedStarter.getRows().add(new Row()); return "seedstartermng"; > @RequestMapping(value="/seedstartermng", params="removeRow">) public String removeRow( final SeedStarter seedStarter, final BindingResult bindingResult, final HttpServletRequest req) < final Integer rowId = Integer.valueOf(req.getParameter("removeRow")); seedStarter.getRows().remove(rowId.intValue()); return "seedstartermng"; >
И теперь мы можем добавить динамическую таблицу в нашу форму:
table> thead> tr> th th:text="#">Rowth> th th:text="#">Varietyth> th th:text="#">Seeds per cellth> th> button type="submit" name="addRow" th:text="#">Add rowbutton> th> tr> thead> tbody> tr th:each="row,rowStat : *"> td th:text="$">1td> td> select th:field="*" > option th:each="var : $" th:value="$" th:text="$">Thymus Thymioption> select> td> td> input type="text" th:field="*" /> td> td> button type="submit" name="removeRow" th:value="$" th:text="#">Remove rowbutton> td> tr> tbody> table>
Достаточно много вещей здесь, но не так много, чтобы не понимать… за исключением одной странной вещи:
select th:field="*__].variety>" > . select>
Если вы помните из учебника «Использование Thymeleaf», то синтаксис __$__ является выражением предварительной обработки, которое является внутренним выражением, которое вычисляется до фактической оценки всего выражения. Но почему такой способ указания индекса строки? Не будет ли этого достаточно с:
select th:field="*"> . select>
…вообще-то нет. Проблема в том, что Spring EL не оценивает переменные в скобках индекса массива, поэтому при выполнении вышеприведенного выражения мы получим ошибку, сообщающую нам, что rows[rowStat.index] (вместо rows[0], rows[1] и т. д.) недопустимая позиция в коллекции строк. Вот почему здесь необходима предварительная обработка.
Давайте посмотрим на фрагмент полученного HTML-кода после того, как несколько раз нажали «Add Row»:
tbody> tr> td>1td> td> select id="rows0.variety" name="rows[0].variety"> option selected="selected" value="1">Thymus vulgarisoption> option value="2">Thymus x citriodorusoption> option value="3">Thymus herba-baronaoption> option value="4">Thymus pseudolaginosusoption> option value="5">Thymus serpyllumoption> select> td> td> input id="rows0.seedsPerCell" name="rows[0].seedsPerCell" type="text" value="" /> td> td> button name="removeRow" type="submit" value="0">Remove rowbutton> td> tr> tr> td>2td> td> select id="rows1.variety" name="rows[1].variety"> option selected="selected" value="1">Thymus vulgarisoption> option value="2">Thymus x citriodorusoption> option value="3">Thymus herba-baronaoption> option value="4">Thymus pseudolaginosusoption> option value="5">Thymus serpyllumoption> select> td> td> input id="rows1.seedsPerCell" name="rows[1].seedsPerCell" type="text" value="" /> td> td> button name="removeRow" type="submit" value="1">Remove rowbutton> td> tr> tbody>
Смотри также популярное:
Зачем нужна Java. http://fetisovvs.blogspot.com/2014/07/java.html Когда Java наконец помрёт, что с этим делать и что будет с JPoint. https://fetisovvs.blogspot.com/2018/11/java-jpoint-java.html
Разбор основных концепций параллелизма. http://fetisovvs.blogspot.com/2018/04/java.html Первый контакт с «var» в Java 10. http://fetisovvs.blogspot.com/2018/01/var-java-10-java.html JAVA 9. Что нового? http://fetisovvs.blogspot.com/2017/10/java-9-java.html Руководство по Java 9 для тех, кому приходится работать с legacy-кодом. http://fetisovvs.blogspot.com/2018/08/java-9-legacy-java.html Концепции объектно-ориентированного программирования — ООП в Java. http://fetisovvs.blogspot.com/2017/01/java-java.html Анимации в Android по полочкам (Часть 1. Базовые анимации). http://fetisovvs.blogspot.com/2018/02/android-1-java.html Двести пятьдесят русскоязычных обучающих видео докладов и лекций о Java. http://fetisovvs.blogspot.com/2015/12/java-5-java-java.html Абстрактные классы и методы. http://fetisovvs.blogspot.com/2017/02/java.html Полное руководство по Java Reflection API. Рефлексия на примерах. http://fetisovvs.blogspot.com/2017/02/java-reflection-api-java.html Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. http://fetisovvs.blogspot.com/2017/10/java-java.html Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. (Часть 3). http://fetisovvs.blogspot.com/2017/10/java-3-java.html ТОП-3 способа конвертировать массив в ArrayList. Пример на Java. http://fetisovvs.blogspot.com/2016/09/3-arraylist-java-java.html Ввод–вывод в Java. http://fetisovvs.blogspot.com/2016/05/java-java_28.html Java Challengers #2: Сравнение строк. https://fetisovvs.blogspot.com/2018/11/java-challengers-2-java.html Enum-Всемогущий. http://fetisovvs.blogspot.com/2017/02/enum-java.html Массивы в Java. Создание и обработка. http://fetisovvs.blogspot.com/2017/10/java-java_18.html Arrays, Collections: Алгоритмический минимум. http://fetisovvs.blogspot.com/2017/12/arrays-collections.html Популярные методы для работы с Java массивами. http://fetisovvs.blogspot.com/2016/09/java-java_29.html Пример использования метода replace в Java. Как заменить символ в строке? http://fetisovvs.blogspot.com/2017/01/replace-java-java.html Класс Scanner в Java — описание и пример использования. http://fetisovvs.blogspot.com/2017/01/scanner-java-java.html Пример использования метода trim в Java: как удалить пробелы в начале и конце строки? http://fetisovvs.blogspot.com/2017/01/trim-java-java.html Spark — Потрясающий веб-микрофреймворк для Java. http://fetisovvs.blogspot.com/2017/10/spark-java-java.html Чтение и запись CSV файла с помощью SuperCSV. http://fetisovvs.blogspot.com/2017/01/csv-supercsv-java-java.html Конструкция try/catch/finally (исключения). http://fetisovvs.blogspot.com/2017/01/trycatchfinally-java.html 1000+ часов видео по Java на русском. http://fetisovvs.blogspot.nl/2017/06/1000-java-java.html Раздача халявы: нетормозящие треды в Java. Project Loom. http://fetisovvs.blogspot.com/2018/09/java-project-loom-java.html Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку. http://fetisovvs.blogspot.com/2016/04/java-71-inputstream-java.html Шпаргалки Java программиста 10: Lombok. http://fetisovvs.blogspot.nl/2017/12/java-10-lombok-java.html Шпаргалки Java программиста 9: Java SE — Шпаргалка для собеседований и повторений. http://fetisovvs.blogspot.com/2017/12/java-9-java-se-java.html Шпаргалка Java программиста 8. Библиотеки для работы с Json (Gson, Fastjson, LoganSquare, Jackson, JsonPath и другие). http://fetisovvs.blogspot.com/2016/04/java-8-json-gson-fastjson-logansquare.html Java 8 и паттерн Стратегия. http://fetisovvs.blogspot.com/2018/03/java-8-java.html Java EE Concurency API. http://fetisovvs.blogspot.com/2018/08/java-ee-concurency-api-java.html Реализация ООП-наследования в классах, работающих с SQL и MS Entity Framework. http://fetisovvs.blogspot.com/2017/02/sql-ms-entity-framework.html Как установить соединение с СУБД MySQL в IntelliJ IDEA в редакции Community. http://fetisovvs.blogspot.com/2016/04/mysql-intellij-idea-community-java.html TDD приложений на Spring Boot: работа с базой данных. https://fetisovvs.blogspot.com/2018/12/tdd-spring-boot-java.html Руководство: Thymeleaf + Spring. Часть 1. https://fetisovvs.blogspot.com/2019/01/thymeleaf-spring-1-java.html Введение в Spring Boot: создание простого REST API на Java. https://fetisovvs.blogspot.com/2019/01/spring-boot-rest-api-java-java.html Всегда ли нужны Docker, микросервисы и реактивное программирование? https://fetisovvs.blogspot.com/2019/01/docker-java.html Максимально простой в поддержке способ интеграции java-клиента с java-сервером. http://fetisovvs.blogspot.com/2018/09/java-java-java.html AOP vs Функции. https://fetisovvs.blogspot.com/2019/01/aop-vs-java.html Как с помощью maven работать с библиотеками, которых в maven нет. http://fetisovvs.blogspot.com/2017/03/maven-maven-java.html Проекты по созданию компиляторов из Java в JavaScript и исполняемые файлы. http://fetisovvs.blogspot.com/2018/01/java-javascript-java.html Реактивное программирование с JAX-RS. http://fetisovvs.blogspot.com/2018/09/jax-rs-java.html Компактные строки в Java 9. https://fetisovvs.blogspot.com/2018/10/java-9-java.html Динамический прокси Java: что это и как им пользоваться? https://fetisovvs.blogspot.com/2018/12/java-java.html Абстрактный CRUD от репозитория до контроллера: что ещё можно сделать при помощи Spring + Generics. http://fetisovvs.blogspot.com/2018/09/crud-spring-generics-java.html Диагностика утечек памяти в Java. http://fetisovvs.blogspot.com/2017/03/java-java_18.html Java, Spring, Kurento и медиасервисы.https://fetisovvs.blogspot.com/2019/01/java-spring-kurento-java.html https://fetisovvs.blogspot.com/2019/01/java-spring-kurento-2-java.html Spring AOP и JavaConfig в плагинах для Atlassian Jira. http://fetisovvs.blogspot.com/2018/04/spring-aop-javaconfig-atlassian-jira.html Маппинг запросов на Netty. https://fetisovvs.blogspot.com/2019/01/netty-java.html Блеск и нищета Java для настольных систем. http://fetisovvs.blogspot.com/2018/04/java-haulmont-java.html Разбор задачек от Одноклассников на JPoint 2018. http://fetisovvs.blogspot.com/2018/04/jpoint-2018-java.html Программируем… выход из лабиринта. http://fetisovvs.blogspot.com/2015/10/java.html Основы работы с IntelliJ IDEA. Интерфейс программы. http://fetisovvs.blogspot.com/2016/09/intellij-idea-java.html Ускоряем время сборки и доставки java web приложения. http://fetisovvs.blogspot.com/2018/03/java-web-java.html Открытый урок Java Enterprise «CDI in action». http://fetisovvs.blogspot.com/2018/09/java-enterprise-cdi-in-action-java.html «Мы все стремимся к сложности, а потом с ней боремся»: интервью с Венкатом Субраманиамом. http://fetisovvs.blogspot.com/2018/09/java_16.html