CommandButton / CommandLink / ajax-действие / метод прослушивателя не вызван или входное значение не установлено / обновлено
-
22-09-2019 - |
Вопрос
Иногда, при использовании <h:commandLink>
, <h:commandButton>
или <f:ajax>
, тот самый action
, actionListener
или listener
метод, связанный с тегом, просто не вызывается.Или свойства компонента не обновляются с помощью отправленных UIInput
ценности.
Каковы возможные причины и пути решения этого?
Решение
Введение
Всякий раз, когда UICommand
компонент (<h:commandXxx>
, <p:commandXxx>
, и т.д.) не удается вызвать связанный метод действия, или UIInput
компонент (<h:inputXxx>
, <p:inputXxxx>
, и т.д.) Не удается обработать отправленные значения и / или обновить значения модели, и вы не видите никаких googlable исключений и / или предупреждений в журнале сервера, также не при настройке обработчика исключений ajax в соответствии с Обработка исключений в ajax-запросах JSF, ни когда вы устанавливаете приведенный ниже параметр контекста в web.xml
,
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
и вы также не видите никаких ошибок googlable и / или предупреждений в консоли JavaScript браузера (нажмите F12 в Chrome / Firefox23 + / IE9 +, чтобы открыть набор инструментов веб-разработчика, а затем откройте Консоль вкладка), затем проработайте приведенный ниже список возможных причин.
Возможные причины
UICommand
иUIInput
компоненты должны быть помещены внутриUIForm
компонент, например<h:form>
(и, следовательно, не обычный HTML<form>
), в противном случае ничего не может быть отправлено на сервер.UICommand
компоненты также не должны иметьtype="button"
атрибут, в противном случае это будет мертвая кнопка, которая полезна только для JavaScriptonclick
.Смотрите также Как отправить входные значения формы и вызвать метод в компоненте JSF и <h:commandButton> не инициирует обратную отправку.Вы не можете вложить несколько
UIForm
компоненты друг в друге.Это незаконно в HTML.Поведение браузера не определено.Будьте осторожны с включаемыми файлами!Вы можете использоватьUIForm
компоненты работают параллельно, но они не будут обрабатывать друг друга во время отправки.Вам также следует быть осторожным с антипаттерном "Форма бога";убедитесь, что вы непреднамеренно не обрабатываете / не проверяете все другие (невидимые) входные данные в той же форме (напримерналичие скрытого диалогового окна с требуемыми входными данными в той же форме).Смотрите также Как использовать <h:form> на странице JSF?Единая форма?Множественные формы?Вложенные формы?.НЕТ
UIInput
должна была произойти ошибка проверки значения / преобразования.Вы можете использовать<h:messages>
для отображения любых сообщений, которые не отображаются с помощью каких-либо специфичных для ввода данных<h:message>
Компоненты.Не забудьте включитьid
из<h:messages>
в<f:ajax render>
, если таковой имеется, чтобы он также обновлялся при ajax-запросах.Смотрите также h: messages не отображает сообщения при нажатии кнопки p: CommandButton.Если
UICommand
илиUIInput
компоненты помещаются внутри повторяющегося компонента, например<h:dataTable>
,<ui:repeat>
, и т.д., то вам нужно убедиться, что точно такой жеvalue
часть итеративного компонента была сохранена на этапе применения значений запроса запроса отправки формы.JSF повторит его, чтобы найти нажатую ссылку / кнопку и отправленные входные значения.Помещаем компонент в область представления и / или убеждаемся, что вы загружаете модель данных в@PostConstruct
из компонента (и, следовательно, не в методе getter!) следует исправить это.Смотрите также Как и когда я должен загрузить модель из базы данных для h:DataTable.Если
UICommand
илиUIInput
компоненты включаются динамическим источником, таким как<ui:include src="#{bean.include}">
, затем вам нужно убедиться, что точно такой же#{bean.include}
значение сохраняется во время построения представления запроса на отправку формы.JSF повторно выполнит его во время построения дерева компонентов.Помещаем компонент в область представления и / или убеждаемся, что вы загружаете модель данных в@PostConstruct
из компонента (и, следовательно, не в методе getter!) следует исправить это.Смотрите также Как обновить динамическое включение содержимого в ajax с помощью меню навигации?(СПА-центр JSF).Тот Самый
rendered
атрибут компонента и всех его родительских элементов, а такжеtest
атрибут любого родительского элемента<c:if>
/<c:when>
не следует оценивать поfalse
на этапе "Применить значения запроса" формы "Отправить запрос".JSF перепроверит это как часть защиты от фальсифицированных / взломанных запросов.Хранение переменных, ответственных за условие, в@ViewScoped
bean или убедиться, что вы правильно выполняете предварительную инициализацию условия в@PostConstruct
из a@RequestScoped
бин должен это исправить.То же самое относится и кdisabled
атрибут компонента, который не должен оцениваться какtrue
на этапе применения значений запроса.Смотрите также Действие командной кнопки JSF не вызвано и Отправка формы в условно отображаемом компоненте не обрабатывается.Тот Самый
onclick
атрибутUICommand
компонент иonsubmit
атрибутUIForm
компонент не должен возвращатьfalse
или вызвать ошибку JavaScript.Там должно быть в случае<h:commandLink>
или<f:ajax>
также не должно быть видно ошибок JS в консоли JS браузера.Обычно поиск в Google точного сообщения об ошибке уже даст вам ответ.Смотрите также Добавление jQuery к PrimeFaces приводит к неперехваченным ошибкам типа.Если вы используете Ajax через JSF 2.x
<f:ajax>
или , например ,Основные лица<p:commandXxx>
, убедитесь, что у вас есть<h:head>
в главном шаблоне вместо<head>
.В противном случае JSF не сможет автоматически включать необходимые файлы JavaScript, содержащие функции Ajax.Это привело бы к ошибке JavaScript типа "mojarra не определен" или "PrimeFaces не определен" в консоли JS браузера.Смотрите также h: CommandLink actionlistener не вызывается при использовании с f: ajax и ui:repeat.Если вы используете Ajax, и представленные значения в конечном итоге будут
null
, затем убедитесь , чтоUIInput
иUICommand
компоненты, представляющие интерес, охватываются<f:ajax execute>
или , например ,<p:commandXxx process>
, в противном случае они не будут выполнены / обработаны.Смотрите также Отправленные значения формы не обновляются в модели при добавлении <f:ajax> Для <h:commandButton> и Понимание атрибутов процесса / обновления PrimeFaces и JSF f: ajax execute / render.Если представленные значения по-прежнему оказываются равными
null
, и вы используете CDI для управления компонентами, затем убедитесь, что вы импортируете аннотацию области из правильного пакета, иначе CDI по умолчанию будет иметь значение@Dependent
который эффективно воссоздает компонент при каждом отдельном вычислении выражения EL.Смотрите также компонент @SessionScoped теряет область видимости и постоянно воссоздается заново, поля становятся нулевыми и Какова область управляемого компонента по умолчанию в приложении JSF 2?Если родитель
<h:form>
с помощьюUICommand
кнопка предварительно была отрисована / обновлена ajax-запросом, поступающим из другой формы на той же странице, тогда первое действие всегда будет завершаться неудачей в JSF 2.2 или более поздней версии.Второе и последующие действия будут работать.Это вызвано ошибкой в обработке состояния представления, о которой сообщается как Спецификация JSF выпуск 790 и в настоящее время исправлен в JSF 2.3.Для более старых версий JSF вам необходимо явно указать идентификатор<h:form>
вrender
из числа<f:ajax>
.Смотрите также h:commandButton/h:commandLink не работает при первом нажатии, работает только при втором.Если
<h:form>
имеетenctype="multipart/form-data"
устанавливается для поддержки загрузки файлов, тогда вам нужно убедиться, что вы используете по крайней мере JSF 2.2 или что фильтр сервлетов, который отвечает за анализ запросов с составными частями / данными формы, правильно настроен, в противном случаеFacesServlet
в конечном итоге вы вообще не получите параметров запроса и, следовательно, не сможете применить значения запроса.Способ настройки такого фильтра зависит от используемого компонента загрузки файла.Для Томагавка<t:inputFileUpload>
, проверить этот ответ и для первичных лиц<p:fileUpload>
, проверить этот ответ.Или, если вы на самом деле вообще не загружаете файл, то вообще удалите атрибут.Убедитесь, что
ActionEvent
аргумент оactionListener
являетсяjavax.faces.event.ActionEvent
и, таким образом, неjava.awt.event.ActionEvent
, что и предлагается большинством IDE в качестве 1-го варианта автозаполнения.Отсутствие аргументов также неправильно, если вы используетеactionListener="#{bean.method}"
.Если вам не нужен аргумент в вашем методе, используйтеactionListener="#{bean.method()}"
.Или, возможно, вы действительно хотите использоватьaction
вместо того, чтобыactionListener
.Смотрите также Различия между action и ActionListener.Убедитесь, что нет
PhaseListener
или любой другойEventListener
в цепочке запрос-ответ изменен жизненный цикл JSF, чтобы пропустить фазу действия вызова, например, вызвавFacesContext#renderResponse()
илиFacesContext#responseComplete()
.Убедитесь, что нет
Filter
илиServlet
в той же цепочке запрос-ответ был заблокирован запрос дляFacesServlet
каким-то образом.Если вы используете простые интерфейсы
<p:dialog>
или<p:overlayPanel>
, затем убедитесь, что у них есть свои собственные<h:form>
.Потому что эти компоненты по умолчанию с помощью JavaScript перемещены в конец HTML<body>
.Итак, если они изначально сидели внутри<form>
, тогда они теперь больше не сидели бы в<form>
.Смотрите также p: действие commandbutton не работает внутри p: dialogОшибка в фреймворке.Например, в RichFaces есть "ошибка преобразования" при использовании
rich:calendar
Элемент пользовательского интерфейса сdefaultLabel
атрибут (или, в некоторых случаях,rich:placeholder
подэлемент).Эта ошибка предотвращает вызов метода bean, если для календарной даты не задано значение.Отслеживание ошибок фреймворка может быть выполнено, если начать с простого рабочего примера и создавать резервную копию страницы до тех пор, пока ошибка не будет обнаружена.
Подсказки по отладке
На случай, если у вас все еще заедает, пришло время отлаживать.На стороне клиента нажмите F12 в webbrowser, чтобы открыть набор инструментов веб-разработчика.Нажмите на кнопку Консоль вкладка, так что смотрите обзор JavaScript.В нем не должно быть никаких ошибок JavaScript.На приведенном ниже скриншоте приведен пример из Chrome, который демонстрирует случай отправки <f:ajax>
включенная кнопка при отсутствии <h:head>
объявлено (как описано в пункте 7 выше).
Нажмите на кнопку Сеть вкладка для просмотра монитора HTTP-трафика.Отправьте форму и проверьте, соответствуют ли заголовки запроса, данные формы и тело ответа ожиданиям.На скриншоте ниже приведен пример из Chrome, который демонстрирует успешную отправку простой формы с помощью ajax с одним <h:inputText>
и один - единственный <h:commandButton>
с <f:ajax execute="@form" render="@form">
.
(предупреждение:когда вы публикуете скриншоты из заголовков HTTP-запросов, подобных приведенным выше, из производственной среды, убедитесь, что вы скремблируете / затемняете все сеансовые файлы cookie на скриншоте, чтобы избежать атак с перехватом сеанса!)
На стороне сервера убедитесь, что сервер запущен в режиме отладки.Установите точку останова отладки в методе интересующего компонента JSF, который, как вы ожидаете, будет вызван во время обработки отправки формы.Например.в случае UICommand
компонент, который был бы UICommand#queueEvent()
и в случае UIInput
компонент, который был бы UIInput#validate()
.Просто выполните пошаговое выполнение кода и проверьте, соответствуют ли поток и переменные ожиданиям.На скриншоте ниже приведен пример из отладчика Eclipse.
Другие советы
Если ваш h:commandLink
находится внутри h:dataTable
есть еще одна причина, почему h:commandLink
может не сработать:
Базовый источник данных, который привязан к h:dataTable
также должен быть доступен во втором жизненном цикле JSF, который запускается при нажатии ссылки.
Таким образом, если базовый источник данных ограничен областью запроса, h:commandLink
не работает!
Хотя мой ответ не на 100% применим, но большинство поисковых систем считают это первым попаданием, я тем не менее решил опубликовать его:
Если вы используете PrimeFaces (или какой-нибудь аналогичный API) p:commandButton
или p:commandLink
, скорее всего, вы забыли явно добавить process="@this"
к вашим командным компонентам.
Как указано в Руководстве пользователя PrimeFaces в разделе 3.18, значения по умолчанию для process
и update
оба @form
, что в значительной степени противоречит настройкам по умолчанию, которые вы могли бы ожидать от простого JSF. f:ajax
или RichFaces, которые execute="@this"
и render="@none"
соответственно.
Просто мне потребовалось ооочень много времени, чтобы это выяснить.(...и я думаю, что использовать значения по умолчанию, отличные от JSF, довольно глупо!)
Я хотел бы упомянуть еще одну вещь, касающуюся Primefaces. p:commandButton
!
Когда вы используете p:commandButton
для действия, которое необходимо совершить на сервере, вы не можете использовать type="button"
потому что это для Нажмите на кнопки которые используются для выполнения пользовательского javascript без вызова запроса ajax/non-ajax на сервер.
Для этого вы можете отказаться от type
атрибут (значение по умолчанию "submit"
) или вы можете явно использовать type="submit"
.
Надеюсь, это кому-то поможет!
Сам застрял в этой проблеме и нашел еще одну причину этой проблемы.Если в вашем компоненте поддержки нет методов установки для свойств, используемых в вашем *.xhtml , то действие просто не вызывается.
Недавно я столкнулся с проблемой, когда UICommand не вызывается в приложении JSF 1.2 с использованием компонентов IBM Extended Faces.
У меня была командная кнопка в строке таблицы данных (расширенная версия, поэтому <hx:datatable>
), и UICommand не сработал бы для определенных строк таблицы (строки, которые не сработали бы, были строками, размер которых превышал размер отображения строки по умолчанию).
У меня был раскрывающийся компонент для выбора количества отображаемых строк.Значение, поддерживающее это поле, было в RequestScope
.Данные, лежащие в основе самой таблицы, находились в своего рода ViewScope
(реально временно в SessionScope
).
Если отображение строки было увеличено с помощью элемента управления, значение которого также было привязано к таблице данных rows
атрибут, ни одна из строк, отображаемых в результате этого изменения, не могла активировать UICommand при нажатии.
Помещение этого атрибута в ту же область, что и сами данные таблицы, устранило проблему.
Я думаю, что об этом упоминалось в BalusC #4 выше, но не только значение таблицы должно быть ограничено областью просмотра или сеанса, но также и атрибут, контролирующий количество строк, отображаемых в этой таблице.
У меня тоже была эта проблема, и я начал выяснять ее причину только после открытия веб-консоли браузера.До этого я не мог получить никаких сообщений об ошибках (даже при <p:messages>
).Веб-консоль показывала код состояния HTTP 405, возвращающийся из <h:commandButton type="submit" action="#{myBean.submit}">
.
В моем случае у меня есть смесь ванильных HttpServlet, обеспечивающих аутентификацию OAuth через фасеты Auth0 и JSF, а также bean-компоненты, выполняющие представления моего приложения и бизнес-логику.
Как только я провел рефакторинг своего web.xml и удалил сервлет-посредник, он «волшебным образом» заработал.
Суть в том, что проблема заключалась в том, что сервлет-посредник использовал RequestDispatcher.forward(...) для перенаправления из среды HttpServlet в среду JSF, тогда как сервлет, вызываемый до него, перенаправлялся с помощью HttpServletResponse.sendRedirect(.. .).
По сути, использование sendRedirect() позволило «контейнеру» JSF взять на себя управление, тогда как RequestDispatcher.forward(), очевидно, этого не сделал.
Чего я не знаю, так это того, почему facelet смог получить доступ к свойствам компонента, но не смог их установить, и это явно требует отказа от смеси сервлетов и JSF, но я надеюсь, что это поможет кому-то избежать многих часов головной боли. стук по столу.
Мне было очень весело отлаживать проблему, из-за которой <h:commandLink>
действия в richfaces
datatable
отказался стрелять.В какой-то момент стол работал, но перестал работать без видимой причины.Я не оставил камня на камне, только чтобы узнать, что мой rich:datatable
использовал неправильно rowKeyConverter
который возвращал нули, которые richfaces с радостью использовали в качестве ключей строк.Это помешало моему <h:commandLink>
действие от получения вызова.
Еще одна возможность:Если признаком является то, что первый вызов работает, а последующие нет, возможно, вы используете PrimeFaces 3.x с JSF 2.2, как подробно описано здесь: ViewState не отправляется.
Я исправил проблему с размещением:
<h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>
В:
<h:form>
<h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>
</h:form>
<ui:composition>
<h:form id="form1">
<p:dialog id="dialog1">
<p:commandButton value="Save" action="#{bean.method1}" /> <!--Working-->
</p:dialog>
</h:form>
<h:form id="form2">
<p:dialog id="dialog2">
<p:commandButton value="Save" action="#{bean.method2}" /> <!--Not Working-->
</p:dialog>
</h:form>
</ui:composition>
Решать;
<ui:composition>
<h:form id="form1">
<p:dialog id="dialog1">
<p:commandButton value="Save" action="#{bean.method1}" /> <!-- Working -->
</p:dialog>
<p:dialog id="dialog2">
<p:commandButton value="Save" action="#{bean.method2}" /> <!--Working -->
</p:dialog>
</h:form>
<h:form id="form2">
<!-- .......... -->
</h:form>
</ui:composition>