Иногда при использовании <h:commandLink>
, <h:commandButton>
или <f:ajax>
метод action
, actionListener
или listener
, связанный с тегом, просто не вызывается. Или, свойства bean не обновляются с представленными значениями UIInput
.
Каковы возможные причины и решения для этого?
Ответ 1
Вступление
Всякий раз, когда компонент 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>
вы также не видите никаких ошибок и/или предупреждений, связанных с Google, в консоли браузера JavaScript (нажмите F12 в Chrome/Firefox23+/IE9 +, чтобы открыть набор инструментов веб-разработчика, а затем откройте вкладку "Консоль"), затем просмотрите приведенный ниже список возможных причин.,
Возможные причины
-
UICommand
и UIInput
должны быть размещены внутри компонента UIForm
, например, <h:form>
(и, следовательно, не в виде простого HTML <form>
), иначе на сервер ничего нельзя отправить. Компоненты UICommand
также не должны иметь атрибут type="button"
, иначе это будет мертвая кнопка, которая полезна только для JavaScript при onclick
. Смотрите также Как отправить входные значения формы и вызвать метод в bean-компоненте JSF, и <h: commandButton> не инициирует обратную передачу.
-
Вы не можете UIForm
несколько компонентов UIForm
друг в друга. Это незаконно в HTML. Поведение браузера не определено. Остерегайтесь включаемых файлов! Вы можете использовать компоненты UIForm
параллельно, но они не будут обрабатывать друг друга во время отправки. Вы также должны остерегаться "антипаттерна формы Бога"; убедитесь, что вы непреднамеренно не обрабатываете/не проверяете все другие (невидимые) входные данные в той же форме (например, наличие скрытого диалога с необходимыми входными данными в той же форме). Смотрите также Как использовать <h: form> на странице JSF? Одиночная форма? Несколько форм? Вложенные формы? ,
-
UIInput
проверки/преобразования значения UIInput
должна была возникнуть. Вы можете использовать <h:messages>
для отображения любых сообщений, которые не отображаются никакими компонентами <h:message>
специфичными для ввода. Не забудьте включить id
<h:messages>
в <f:ajax render>
, если таковой имеется, чтобы он также обновлялся при запросах ajax. См. Также h: messages не отображает сообщения при нажатии кнопки p: commandButton.
-
Если компоненты UICommand
или UIInput
находятся внутри UIInput
компонента, такого как <h:dataTable>
, <ui:repeat>
и т.д., <h:dataTable>
необходимо убедиться, что на этапе применения значений запроса применяется одно и то же value
итерационного компонента. Форма отправки запроса. JSF будет повторять его, чтобы найти нажатую ссылку/кнопку и ввести введенные значения. Помещение компонента в область видимости и/или @PostConstruct
загрузки модели данных в @PostConstruct
компонента (и, следовательно, не в методе получения!) Должны исправить это. Смотрите также Как и когда я должен загрузить модель из базы данных для h: dataTable.
-
Если компоненты UICommand
или UIInput
включены динамическим источником, таким как <ui:include src="#{bean.include}">
, то необходимо убедиться, что во время просмотра сохраняется точно такое же значение #{bean.include}
Время сборки формы отправить запрос. JSF повторно выполнит его во время построения дерева компонентов. Помещение компонента в область видимости и/или @PostConstruct
загрузки модели данных в @PostConstruct
компонента (и, следовательно, не в методе получения!) Должны исправить это. См. Также Как ajax-refresh динамически включать контент с помощью меню навигации? (JSF SPA).
-
rendered
атрибут компонента и все его родителей и test
атрибут любого родителя <c:if>
/<c:when>
не следуют оценивать по false
во время запроса применяется значение фазы подчиненной формы запроса. JSF будет перепроверять его как часть защиты от подделанных/взломанных запросов. Хранение переменных, отвечающих за условие, в компоненте @ViewScoped
или @ViewScoped
правильности предварительной @PostConstruct
условия в @PostConstruct
компонента @RequestScoped
должны исправить это. То же самое относится и к disabled
атрибуту компонента, который не должен иметь значение true
во время фазы применения значений запроса. См. Также действие JSF CommandButton, которое не вызывается, и отправка формы в условно отображаемом компоненте не обрабатывается.
-
onclick
атрибут UICommand
компонента и onsubmit
атрибут UIForm
компоненты не должен возвращать false
или вызвать ошибку JavaScript. В случае <h:commandLink>
или <f:ajax>
также не должно быть никаких ошибок JS, видимых в консоли JS браузера. Обычно поиск точного сообщения об ошибке уже даст вам ответ. Смотрите также Добавление jQuery в PrimeFaces приводит к Uncaught TypeErrors.
-
Если вы используете Ajax через JSF 2.x <f:ajax>
или, например, PrimeFaces <p:commandXxx>
, убедитесь, что у вас есть <h:head>
в главном шаблоне вместо <head>
. В противном случае JSF не сможет автоматически включать необходимые файлы JavaScript, которые содержат функции Ajax. Это может привести к ошибке JavaScript, такой как "mojarra не определен" или "PrimeFaces не определен" в консоли JS браузера. Смотрите также h: commandLink actionlistener не вызывается при использовании с f: ajax и ui: repeat.
-
Если вы используете Ajax, и отправленные значения в конечном итоге UIInput
null
, то убедитесь, что представляющие UIInput
компоненты UIInput
и UICommand
охвачены <f:ajax execute>
или, например, <p:commandXxx process>
, иначе они <p:commandXxx process>
' быть выполненным/обработанным. См. Также Отправленные значения формы, не обновленные в модели, при добавлении <f: ajax> в <h: commandButton> и Понимании процесса/обновления PrimeFaces и атрибутов выполнения/рендеринга JSF f: ajax.
-
Если отправленные значения все равно оказываются null
, и вы используете CDI для управления bean-компонентами, убедитесь, что вы импортируете аннотацию области действия из правильного пакета, иначе CDI по умолчанию будет иметь значение @Dependent
которое эффективно воссоздает bean-компонент при каждой отдельной оценке. выражения EL. См. Также @SessionScoped bean-компонент теряет область видимости и постоянно воссоздается, поля становятся пустыми и какова область действия управляемого компонента по умолчанию в приложении 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 или что фильтр сервлетов, который отвечает за синтаксический анализ запросов multipart/form-data настроен правильно, в противном случае FacesServlet
итоге не получит параметров запроса вообще и, следовательно, не сможет применить значения запроса. Как настроить такой фильтр, зависит от используемого компонента загрузки файла. Для Tomahawk <t:inputFileUpload>
проверьте этот ответ, а для PrimeFaces <p:fileUpload>
проверьте этот ответ. Или, если вы вообще не загружаете файл, удалите атрибут вообще.
-
Убедитесь, что аргумент ActionEvent
для actionListener
является javax.faces.event.ActionEvent
и, следовательно, не java.awt.event.ActionEvent
, что большинство IDE предлагают в качестве первого параметра автозаполнения. Иметь аргументы без аргументов также неправильно, если вы используете actionListener="#{bean.method}"
. Если вам не нужен аргумент в вашем методе, используйте actionListener="#{bean.method()}"
. Или, возможно, вы действительно хотите использовать action
вместо actionListener
. Смотрите также Различия между action и actionListener.
-
Убедитесь, что ни один PhaseListener
ни какой-либо EventListener
в EventListener
запрос-ответ не изменили жизненный цикл JSF для пропуска фазы действия вызова, например, путем вызова FacesContext#renderResponse()
или FacesContext#responseComplete()
.
-
Убедитесь, что ни один Filter
или Servlet
в той же цепочке запрос-ответ каким- FacesServlet
образом не заблокировал запрос FacesServlet
.
-
Если вы используете PrimeFaces <p:dialog>
или <p:overlayPanel>
, убедитесь, что у них есть собственная <h:form>
. Потому что по умолчанию эти компоненты перемещены в конец HTML <body>
. Итак, если бы они изначально сидели внутри <form>
, то теперь они больше не сидели бы в <form>
. См. Также действие p: commandbutton внутри p: не работает
-
Ошибка в рамках. Например, RichFaces имеет " ошибку преобразования " при использовании элемента пользовательского интерфейса rich:calendar
с атрибутом defaultLabel
(или, в некоторых случаях, подэлементом rich:placeholder
). Эта ошибка предотвращает вызов метода bean, если для календарной даты не задано значение. Отследить ошибки в фреймворке можно, начав с простого рабочего примера и создавая страницу обратно, пока ошибка не будет обнаружена.
Советы по отладке
Если вы все еще застряли, пришло время отладки. На стороне клиента нажмите F12 в веб-браузере, чтобы открыть набор инструментов для веб-разработчиков. Перейдите на вкладку "Консоль", чтобы увидеть JavaScript. Он не должен содержать ошибок JavaScript. Ниже на скриншоте показан пример из Chrome, который демонстрирует случай отправки кнопки с включенным <f:ajax>
без объявления <h:head>
(как описано в пункте 7 выше).
![js console]()
Нажмите вкладку Сеть, чтобы увидеть монитор трафика HTTP. Отправьте форму и выясните, соответствуют ли заголовки запроса, данные формы и тело ответа ожиданиям. Ниже на скриншоте показан пример из Chrome, который демонстрирует успешную отправку ajax простой формы с одним <h:inputText>
и одним <h:commandButton>
с <f:ajax execute="@form" render="@form">
![network monitor]()
(предупреждение: когда вы публикуете скриншоты из заголовков HTTP-запросов, как указано выше, из продакшен среды, убедитесь, что вы зашифровываете/скрываете любые сессионные куки файлы на снимке экрана, чтобы избежать атак захвата сессии!)
На стороне сервера убедитесь, что сервер запущен в режиме отладки. Поместите точку останова отладки в метод интересующего компонента JSF, который вы ожидаете вызвать во время обработки отправки формы. Например, в случае компонента UICommand
это будет UICommand#queueEvent()
а в случае компонента UIInput
это будет UIInput#validate()
. Просто выполните выполнение кода и проверьте, соответствуют ли поток и переменные ожиданиям. Ниже на скриншоте приведен пример отладчика Eclipse.
![debug server]()
Ответ 2
Если ваш h:commandLink
находится внутри h:dataTable
есть еще одна причина, по которой h:commandLink
может не работать:
Базовый источник данных, связанный с h:dataTable
также должен быть доступен во втором жизненном h:dataTable
JSF, который запускается при щелчке по ссылке.
Поэтому, если базовый источник данных находится в области запроса, h:commandLink
не работает!
Ответ 3
Хотя мой ответ не применим на 100%, но большинство поисковых систем считают это первым хитом, я решил опубликовать его без изменений:
Если вы используете PrimeFaces (или какой-либо аналогичный API) p:commandButton
или p:commandLink
, скорее всего, вы забыли явно добавить process="@this"
в свои компоненты команды.
Как указано в руководстве пользователя PrimeFaces в разделе 3.18, значения по умолчанию для process
и update
равны @form
, что в значительной степени противоречит значениям по умолчанию, которые вы можете ожидать от простого JSF f:ajax
или RichFaces, которые execute="@this"
и render="@none"
соответственно.
Просто я нашел время, чтобы узнать. (... и я думаю, что это довольно нечисто для использования значений по умолчанию, отличных от JSF!)
Ответ 4
Я бы упомянул еще одну вещь, касающуюся Primefaces p:commandButton
!
Когда вы используете p:commandButton
для действия, которое необходимо выполнить на сервере, вы не можете использовать type="button"
, потому что это для кнопок, которые используются для выполнения пользовательского javascript без вызывая запрос ajax/non-ajax на сервер.
С этой целью вы можете распределить атрибут type
(значение по умолчанию "submit"
) или вы можете явно использовать type="submit"
.
Надеюсь, это поможет кому-то!
Ответ 5
Я сам застрял в этой проблеме и нашел еще одну причину этой проблемы.
Если у вас нет методов setter в вашей поддержке bean для свойств, используемых в вашем *.xhtml, тогда действие просто не вызывается.
Ответ 6
Недавно я столкнулся с проблемой, когда UICommand не вызывался в приложении JSF 1.2 с использованием компонентов IBM Extended Faces.
У меня была кнопка команды в строке datatable (расширенная версия, поэтому <hx:datatable>
), и UICommand не запускал из определенных строк из таблицы (строки, которые не запускались бы, были строками, превышающими значения по умолчанию размер отображения строки).
У меня был раскрывающийся компонент для выбора количества строк для отображения. Значение, поддерживающее это поле, находилось в RequestScope
. Данные, хранящиеся в самой таблице, были в виде ViewScope
(на самом деле, временно в SessionScope
).
Если отображение строки было увеличено с помощью элемента управления, значение которого также было привязано к атрибуту datatable rows
, ни одна из строк, отображаемых в результате этого изменения, не могла запустить UICommand при нажатии.
Размещение этого атрибута в той же области, что и сама таблица данных. Это проблема.
Я думаю, что это упоминается в BalusС# 4 выше, но не только значение таблицы должно быть View или Session scoped, но также атрибут, контролирующий количество строк для отображения в этой таблице.
Ответ 7
У меня тоже была эта проблема, и я действительно начал отталкиваться от основной причины после открытия веб-консоли браузера. До этого я не смог получить никаких сообщений об ошибках (даже с <p:messages>
). Веб-консоль показала код статуса HTTP 405, возвращающийся с <h:commandButton type="submit" action="#{myBean.submit}">
.
В моем случае у меня есть смесь ванильного HttpServlet, обеспечивающего аутентификацию OAuth через Auth0 и JSF facelets и beans, выполняющие представления приложений и бизнес-логику.
Как только я реорганизовал свой web.xml и удалил сервлет среднего уровня, он тогда "волшебным образом" работал.
В итоге, проблема заключалась в том, что сервлет среднего класса использовал RequestDispatcher.forward(...) для перенаправления из среды HttpServlet в среду JSF, тогда как сервлет, вызываемый до этого, перенаправлялся с помощью HttpServletResponse.sendRedirect(...).
В принципе, использование sendRedirect() разрешало "контейнеру" JSF брать контроль, тогда как RequestDispatcher.forward() явно не был.
Я не знаю, почему facelet смог получить доступ к свойствам bean, но не мог их установить, и это явно кричит о том, что он удаляет смесь сервлетов и JSF, но я надеюсь, что это поможет кому-то избежать много часов головокружительного удара.
Ответ 8
Мне было очень весело отлаживать проблему, когда действие <h:commandLink>
в richfaces
datatable
не срабатывало. Таблица использовалась для работы в какой-то момент, но прекратилась без видимых причин. Я не оставил камня на камне, только чтобы узнать, что мой rich:datatable
использовал неправильный rowKeyConverter
, который возвращал nulls, которые richfaces счастливо использовались в качестве ключей строки. Это предотвратило получение моего действия <h:commandLink>
.
Ответ 9
Еще одна возможность: если симптом заключается в том, что первый вызов работает, но последующих нет, вы можете использовать PrimeFaces 3.x с JSF 2.2, как описано здесь: Нет ViewState отправляется.
Ответ 10
<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>
Ответ 11
Я исправил мою проблему с размещением:
<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>