commandButton / commandLink / ajax действие / метод слушателя не вызван или входное значение не установлено / обновлено - PullRequest
327 голосов
/ 22 января 2010

Иногда при использовании <h:commandLink>, <h:commandButton> или <f:ajax> метод action, actionListener или listener, связанный с тегом, просто не вызывается. Или свойства компонента не обновляются с использованием отправленных значений UIInput.

Каковы возможные причины и решения для этого?

Ответы [ 10 ]

657 голосов
/ 22 января 2010

Введение

Всякий раз, когда компонент UICommand (<h:commandXxx>, <p:commandXxx> и т. Д.) Не может вызвать связанный метод действия, или компонент UIInput (<h:inputXxx>, <p:inputXxxx> и т. Д.) Не может обработать отправленное значения и / или обновите значения модели, и вы не увидите никаких исключений и / или предупреждений, связанных с googlable, в журнале сервера, в том числе и при настройке обработчика исключений ajax согласно Обработка исключений в запросах JSF ajax, ни когда вы устанавливаете параметр контекста ниже web.xml,

<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
</context-param>

и вы также не видите никаких погугливаемых ошибок и / или предупреждений в консоли JavaScript браузера (нажмите F12 в Chrome / Firefox23 + / IE9 +, чтобы открыть набор инструментов веб-разработчика, а затем откройте вкладку Консоль ), затем Проработайте приведенный ниже список возможных причин.

Возможные причины

  1. UICommand и UIInput должны быть размещены внутри компонента UIForm, например <h:form> (и, следовательно, не простой HTML <form>), в противном случае ничего не может быть отправлено на сервер. Компоненты UICommand также не должны иметь атрибута type="button", в противном случае это будет мертвая кнопка, полезная только для JavaScript onclick. См. Также Как отправлять входные значения формы и вызывать метод в компоненте JSF , а не инициирует обратную передачу .

  2. Вы не можете вложить несколько UIForm компонентов друг в друга. Это незаконно в HTML. Поведение браузера не определено. Остерегайтесь включаемых файлов! Вы можете использовать UIForm компонентов параллельно, но они не будут обрабатывать друг друга во время отправки. Вы также должны остерегаться «антипаттерна формы Бога»; убедитесь, что вы непреднамеренно не обрабатываете / не проверяете все другие (невидимые) входные данные в той же форме (например, наличие скрытого диалога с необходимыми входными данными в той же форме). См. Также Как использовать на странице JSF? Одиночная форма? Несколько форм? Вложенные формы? .

  3. Нет UIInput Ошибка проверки / преобразования значения должна была произойти. Вы можете использовать <h:messages>, чтобы показать любые сообщения, которые не отображаются никакими специфичными для ввода компонентами <h:message>. Не забудьте включить id из <h:messages> в <f:ajax render>, если таковой имеется, чтобы он также обновлялся при запросах ajax. См. Также h: в сообщениях не отображаются сообщения при нажатии кнопки p: commandButton .

  4. Если компоненты UICommand или UIInput размещены внутри итеративного компонента, например <h:dataTable>, <ui:repeat> и т. Д., То необходимо убедиться, что точно такой же value итерационного компонента был сохраняется на этапе применения значений запроса формы отправки запроса. JSF будет повторять его, чтобы найти нажатую ссылку / кнопку и ввести введенные значения. Помещение компонента в область просмотра и / или проверка загрузки модели данных в @PostConstruct компонента (и, следовательно, не в методе получения!) Должны исправить это. См. Также Как и когда я должен загрузить модель из базы данных для h: dataTable .

  5. Если компоненты UICommand или UIInput включены динамическим источником, таким как <ui:include src="#{bean.include}">, необходимо убедиться, что точно такое же значение #{bean.include} сохраняется во время создания представления формы Отправить запрос. JSF повторно выполнит его во время построения дерева компонентов. Помещение компонента в область просмотра и / или проверка загрузки модели данных в @PostConstruct компонента (и, следовательно, не в методе получения!) Должны исправить это. См. Также Как ajax-refresh динамически включать содержимое с помощью меню навигации? (JSF SPA) .

  6. Атрибут rendered компонента и всех его родителей и атрибут test любого родителя <c:if> / <c:when> не должны оцениваться как false во время фазы применения значений запроса Форма отправки запроса. JSF будет перепроверять его как часть защиты от подделанных / взломанных запросов. Хранение переменных, отвечающих за условие, в компоненте @ViewScoped или проверка правильности инициализации условия в @PostConstruct компонента @RequestScoped должно исправить это. То же самое относится к атрибуту disabled компонента, который не должен оцениваться как true на этапе применения значений запроса. См. Также Действие JSF CommandButton не вызвано и Отправка формы в условно отображаемом компоненте не обработана .

  7. Атрибут onclick компонента UICommand и атрибут onsubmit компонента UIForm не должны возвращать false или вызывать ошибку JavaScript. В случае <h:commandLink> или <f:ajax> также не должно быть ошибок JS, видимых в консоли JS браузера. Обычно поиск точного сообщения об ошибке уже даст вам ответ. См. Также Добавление jQuery к PrimeFaces приводит к Uncaught TypeError для всех мест .

  8. Если вы используете 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 .

  9. Если вы используете Ajax, убедитесь, что на UIInput и UICommand представляющие интерес компоненты включены <f:ajax execute> или, например, <p:commandXxx process>, иначе они не будут выполнены / обработаны. См. Также Отправленные значения формы не обновляются в модели при добавлении в и Общие сведения о процессе / обновлении PrimeFaces и JSF f: ajax для атрибутов выполнения / визуализации .

  10. Если родительский элемент <h:form> с кнопкой UICommand был предварительно обработан / обновлен с помощью ajax-запроса, поступающего из другой формы на той же странице, то первое действие всегда будет неудачным. Второе и последующие действия будут работать. Это вызвано ошибкой в ​​обработке состояния представления, которая сообщается как проблема спецификации JSF 790 и в настоящее время планируется исправить в JSF 2.3. Для более старых версий JSF вам необходимо явно указать идентификатор <h:form> в render <f:ajax>. См. Также h: commandButton / h: commandLink не работает при первом нажатии, работает только при втором нажатии .

  11. Если для <h:form> установлено enctype="multipart/form-data", установленное для поддержки загрузки файлов, вам необходимо убедиться, что вы используете хотя бы JSF 2.2 или что фильтр сервлетов отвечает за синтаксический анализ multipart Запросы / form-data настроены правильно, в противном случае FacesServlet в итоге не получит параметров запроса вообще и, следовательно, не сможет применить значения запроса. Как настроить такой фильтр, зависит от используемого компонента загрузки файла. Для Томагавка <t:inputFileUpload> проверьте этот ответ , а для PrimeFaces <p:fileUpload> проверьте этот ответ . Или, если вы вообще не загружаете файл, полностью удалите атрибут.

  12. Убедитесь, что аргумент ActionEvent для actionListener является javax.faces.event.ActionEvent и, следовательно, не java.awt.event.ActionEvent, что большинство IDE предлагает в качестве первого параметра автозаполнения. Если вы не используете аргумент, это также неправильно, если вы используете actionListener="#{bean.method}". Если вам не нужен аргумент в вашем методе, используйте actionListener="#{bean.method()}". Или, возможно, вы действительно хотите использовать action вместо actionListener. См. Также Различия между action и actionListener .

  13. Убедитесь, что ни PhaseListener, ни какие-либо EventListener в цепочке запрос-ответ не изменили жизненный цикл JSF для пропуска фазы действия вызова, например, вызвав FacesContext#renderResponse() или FacesContext#responseComplete().

  14. Убедитесь, что никакие Filter или Servlet в той же цепочке запрос-ответ каким-либо образом не заблокировали запрос FacesServlet.

  15. Ошибка в рамках. Например, RichFaces имеет « ошибка преобразования » при использовании элемента пользовательского интерфейса rich:calendar с атрибутом defaultLabel (или, в некоторых случаях, подэлементом rich:placeholder). Эта ошибка предотвращает вызов метода bean, если для календарной даты не задано значение. Отслеживание ошибок каркаса можно выполнить, начав с простого рабочего примера и создавая страницу обратно до обнаружения ошибки.

  16. Если вы используете PrimeFaces <p:dialog> или <p:overlayPanel>, убедитесь, что у них есть свои <h:form>. Потому что по умолчанию эти компоненты перемещены в конец HTML <body>. Итак, если бы они изначально сидели внутри <form>, то теперь они больше не сидели бы в <form>. См. Также p: действие командной кнопки не работает внутри p: диалоговое окно

Советы по отладке

Если вы все еще застряли, пришло время отладки. На стороне клиента нажмите F12 в веб-браузере, чтобы открыть набор инструментов для веб-разработчиков. Перейдите на вкладку Console , чтобы увидеть консоль 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

52 голосов
/ 09 ноября 2010

Если ваш h:commandLink находится внутри h:dataTable, существует еще одна причина, по которой h:commandLink может не работать:

Базовый источник данных, связанный с h:dataTable, также должен быть доступен во втором жизненном цикле JSF, который запускается при нажатии ссылки.

Таким образом, если базовый источник данных находится в области запроса, h:commandLink не работает!

26 голосов
/ 03 января 2013

Хотя мой ответ не применим на 100%, но большинство поисковых систем считают это первым попаданием, я решил опубликовать его, тем не менее:

Если вы используете PrimeFaces (или некоторый подобный API) p:commandButton или p:commandLink, есть вероятность, что вы забыли явно добавить process="@this" к компонентам вашей команды.

Как указано в Руководстве пользователя PrimeFaces в разделе 3.18, значения по умолчанию для process и update равны @form, что в значительной степени противоречит значениям по умолчанию, которые можно ожидать от простого JSF f:ajax или RichFaces, которые execute="@this" и render="@none" соответственно.

Просто мне понадобилось много времени, чтобы выяснить это. (... и я думаю, что довольно неправильно использовать значения по умолчанию, отличные от JSF!)

9 голосов
/ 03 января 2015

Я бы упомянул еще одну вещь, которая касается Primefaces p:commandButton!

Когда вы используете p:commandButton для действия, которое необходимо выполнить на сервере, вы не можете использовать type="button", потому что это для Кнопки , которые используются для выполнения пользовательского JavaScript без вызова запрос ajax / non-ajax к серверу.

Для этой цели вы можете выдать атрибут type (значение по умолчанию "submit") или вы можете явно использовать type="submit".

Надеюсь, это кому-нибудь поможет!

3 голосов
/ 13 октября 2015

Недавно я столкнулся с проблемой, когда UICommand не вызывается в приложении JSF 1.2 с использованием компонентов IBM Extended Faces.

У меня была командная кнопка в строке таблицы данных (расширенная версия, поэтому <hx:datatable>), и команда UIC не запускалась из определенных строк таблицы (строки, которые не запускались, были строк больше, чем по умолчанию) размер отображения строки).

У меня был выпадающий компонент для выбора количества отображаемых строк. Значение этого поля было в RequestScope. Данные, лежащие в основе самой таблицы, были в некотором роде ViewScope (в действительности, временно в SessionScope).

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

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

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

3 голосов
/ 23 февраля 2013

Я сам застрял в этой проблеме и нашел еще одну причину этой проблемы. Если в вашем компоненте поддержки нет методов установки для свойств, используемых в * .xhtml, то действие просто не вызывается.

2 голосов
/ 11 апреля 2017

У меня тоже была эта проблема, и я действительно начал оттачивать основную причину после открытия веб-консоли браузера. До этого я не мог получить никаких сообщений об ошибках (даже с <p:messages>). В веб-консоли отображался код состояния HTTP 405, возвращаемый с <h:commandButton type="submit" action="#{myBean.submit}">.

В моем случае у меня есть смесь ванильного HttpServlet, обеспечивающего аутентификацию OAuth через Auth0 и JSF-фейлеты и бины, выполняющие представления моего приложения и бизнес-логику.

Как только я реорганизовал свой web.xml и удалил сервлет-посредник, он «волшебным образом» сработал.

В итоге проблема была в том, что сервлет-посредник использовал RequestDispatcher.forward (...) для перенаправления из среды HttpServlet в среду JSF, тогда как вызываемый до этого сервлет перенаправлял с помощью HttpServletResponse.sendRedirect. (...).

По сути, использование sendRedirect () позволило JSF-контейнеру получить контроль, тогда как RequestDispatcher.forward () явно не было.

Чего я не знаю, так это того, почему лицевая сторона смогла получить доступ к свойствам бина, но не смогла их установить, и это явно кричит об отказе от сочетания сервлетов и JSF, но я надеюсь, что это поможет кому-то избежать многих часов ударов головой к столу.

0 голосов
/ 08 февраля 2019

Я исправил проблему с размещением:

<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>
0 голосов
/ 18 августа 2017

Еще одна возможность: если признак в том, что первый вызов работает, а последующие - нет, возможно, вы используете PrimeFaces 3.x с JSF 2.2, как подробно описано здесь: No ViewState не отправляется .

0 голосов
/ 02 мая 2017

Мне было очень весело отлаживать проблему, когда действие <h:commandLink> в richfaces datatable отказывалось срабатывать. Стол раньше работал в какой-то момент, но остановился без видимой причины. Я не оставил камня на камне, только чтобы узнать, что мой rich:datatable использовал неправильный rowKeyConverter, который возвращал нули, которые richfaces с радостью использовали в качестве ключей строк. Это препятствовало тому, чтобы мое <h:commandLink> действие было вызвано.

...