commandButton / commandLink / ajax action / метод слушателя не вызван или входное значение не установлено / обновлено

345

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

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

Мухаммед Хьюди
источник

Ответы:

687

Введение

Всякий раз, когда 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 +, чтобы открыть набор инструментов веб-разработчика, а затем откройте вкладку « Консоль »), затем просмотрите приведенный ниже список возможных причин.

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

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

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

  3. Нет UIInputошибка проверки / преобразования значения не должна была произойти. Вы можете использовать <h:messages>для отображения любых сообщений, которые не отображаются никакими <h:message>компонентами ввода . Не забудьте включить idof <h:messages>в <f:ajax render>, если таковой имеется, чтобы он также обновлялся при запросах ajax. См. Также h: messages не отображает сообщения при нажатии кнопки 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фасоли или убедившись , что вы правильно preinitializing условия в @PostConstructиз @RequestScopedфасоли должны это исправить. То же самое относится и к disabledатрибуту компонента, который не следует оценивать на trueэтапе применения значений запроса. См. Также действие JSF CommandButton, не вызванное , отправка формы в условно отображаемом компоненте не обрабатывается иh: commandButton не работает, когда я обертываю его в <h: panelGroup render> .

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

  8. Если вы используете Ajax через JSF 2.x <f:ajax>или, например, PrimeFaces <p:commandXxx>, убедитесь, что у вас есть <h:head>в шаблоне master вместо <head>. В противном случае JSF не сможет автоматически включать необходимые файлы JavaScript, которые содержат функции Ajax. Это может привести к ошибке JavaScript типа «mojarra не определен» или «PrimeFaces не определен» в консоли JS браузера. См. Также h: commandLink actionlistener не вызывается при использовании с f: ajax и ui: repeat .

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

  10. Если отправленные значения все еще заканчиваются тем null, что вы используете CDI для управления bean-компонентами, убедитесь, что вы импортируете аннотацию области действия из правильного пакета, иначе по умолчанию будет использоваться CDI, @Dependentкоторый эффективно воссоздает bean-компонент при каждой отдельной оценке EL. выражение. Смотрите также @SessionScoped фасоль теряет объем и пересоздался все время, поля утратившим и Что такое по умолчанию Управляемый компонент Scope в JSF 2 приложения?

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

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

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

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

  15. Убедитесь, что ни одна Filterили Servletв той же цепочке запрос-ответ не заблокировала запрос FacesServletкаким-либо образом. Например, фильтры входа / безопасности, такие как Spring Security. Особенно в запросах ajax, которые по умолчанию заканчивались бы вообще без обратной связи с пользовательским интерфейсом. См. Также Обработка запросов Spring Security 4 и PrimeFaces 5 AJAX .

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

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

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

Если вы все еще застряли, пришло время отладки. На стороне клиента нажмите F12 в веб-браузере, чтобы открыть набор инструментов веб-разработчика. Перейдите на вкладку « Консоль », чтобы увидеть консоль JavaScript. Он не должен содержать ошибок JavaScript. Ниже снимок экрана - пример из Chrome, который демонстрирует случай отправки <f:ajax>включенной кнопки, пока она не была <h:head>объявлена ​​(как описано в пункте 7 выше).

консоль js

Нажмите вкладку Сеть, чтобы увидеть монитор трафика HTTP. Отправьте форму и выясните, соответствуют ли заголовки запроса, данные формы и тело ответа ожиданиям. Ниже на скриншоте приведен пример из Chrome, который демонстрирует успешную отправку ajax простой формы с одним <h:inputText>и одним <h:commandButton>с <f:ajax execute="@form" render="@form">.

сетевой монитор

(предупреждение: когда вы публикуете скриншоты из заголовков HTTP-запросов, как указано выше, из производственной среды, убедитесь, что вы зашифровываете / скрываете любые куки-файлы сеанса на снимке экрана, чтобы избежать атак захвата сессии!)

На стороне сервера убедитесь, что сервер запущен в режиме отладки. Поместите точку отладки в метод интересующего компонента JSF, который вы ожидаете вызвать во время обработки отправки формы. Например, в случае UICommandкомпонента это будет, UICommand#queueEvent()а в случае UIInputкомпонента это будет UIInput#validate(). Просто выполните выполнение кода и проверьте, соответствуют ли поток и переменные ожиданиям. Ниже на скриншоте приведен пример отладчика Eclipse.

сервер отладки

BalusC
источник
1
Ваше второе замечание заставило меня задуматься - надолго. Я только что узнал, что тег f: view в моем основном файле был причиной большинства моих проблем. И, вероятно, потому что это делает форму, верно?
Пауло Гуэдес,
2
@pauloguedes Я не могу найти ничего, что утверждает, что f: view отображает форму. Насколько я понимаю, это просто контейнер. По моему опыту, f: view не отображает никаких элементов.
Лукас
@balusc Небольшое пояснение к пункту 4: если commandLink не находится в самой dataTable, имеет ли это значение?
Лукас
спасибо, смысл в том, чтобы поместить бин в область просмотра и / или убедиться, что вы загружаете модель данных в (пост) конструктор бина (и, следовательно, не в методе получения!), это должно исправить это.
merveotesi
2
@Kukeltje: это вызвало бы исключение EL (уже
описанный в
54

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

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

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

jbandi
источник
2
Хорошо, это было не совсем понятно для меня. Я надеюсь, что мой ответ в любом случае будет полезен, поскольку, по крайней мере, в моем случае я не имел дело с UICommand / UIData. «Решением» было продвижение
вспомогательного
1
Второй комментарий Дженса ... установка моего bean-компонента RequestScoped в SessionScoped изменила мою таблицу данных - спасибо
Зак Макомбер,
28

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

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

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

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

Kawu
источник
6
По умолчанию для PrimeFaces processявляется @form. Так что, если действие не вызывается таким образом, но происходит при использовании @this, то наиболее вероятен пункт 3 моего ответа.
BalusC
3
Этого не может быть У меня был p:commandButtonметод, который не вызывал метод actionListener, пока я не добавил process="@this". Кроме того, в Руководстве пользователя PrimeFaces явно перечислены значения по умолчанию, о которых я упоминал в разделах 3.18 и 3.19. Это здесь: primefaces.googlecode.com/files/primefaces_users_guide_3_4.pdf ... может быть, настройки по умолчанию были изменены?
Каву
8
Вероятно, это ошибка в документации. Удалите process="@this"и добавьте <p:messages autoUpdate="true">(или просто прочитайте журнал сервера для помещенных в очередь, но не отображаемых сообщений), и вы увидите, что на самом деле произошла ошибка преобразования / проверки.
BalusC
Почему вы удалили этот вопрос stackoverflow.com/questions/60673695/…
Kukeltje
Я думал, что это не может дать большую ценность сейчас ... Я восстановил это.
Каву
9

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

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

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

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

akelec
источник
это была моя главная проблема на одной из наших страниц, ни один из пунктов в принятом ответе не приблизил нас, где вы нашли эту информацию?
Уриэль Арвизу
Ну, у меня была эта проблема много раз, и я провел исследование и обнаружил, что он p:commandButtonимеет несколько значений typeатрибута и buttonотносится ко всему на стороне клиента. Это немного трудно найти это в Primefacesдок, но вот одна ссылка: developer.am/primefaces/...
akelec
Ваша подсказка подсказки решила мою проблему, с которой я сталкиваюсь уже несколько дней. Большое спасибо за ваш пост!
gpuk360
Спасибо, это мое удовольствие. Я сознательно поставил этот ответ, потому что у многих из нас была такая проблема. Я тоже потерял несколько дней, пока не понял, о чем идет речь.
akelec
3

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

Dnavir
источник
5
Это должно было привести к довольно самоочевидным PropertyNotWritableException. Если вы этого не видели, возможно, вы запустили ajax-запрос без надлежащего обработчика исключений ajax, но вы должны увидеть его в журналах сервера.
BalusC
3
Это не показывало это исключение, пока я не сделал p: commandButton's ajax = "false".
Днавир
СПАСИБО БОГУ, ты спас мне жизнь
exrezzo
3

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

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

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

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

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

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

Брент С
источник
2

У меня тоже была эта проблема, и я действительно начал понимать основную причину после открытия веб-консоли браузера. До этого я не мог получить никаких сообщений об ошибках (даже с <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, но я надеюсь, что это поможет кому-то избежать многих часов головной уборки. к настольному стук.

Brooks
источник
1

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

Мустафа
источник
0

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

Дейв Маллиган
источник
-1

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

<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>
Георги Пеев
источник
Это # 1 в> 600 голосах против. Не нужно писать это как отдельный ответ.
Кукельтье
-1

Это решение, которое работает для меня.

<p:commandButton id="b1" value="Save" process="userGroupSetupForm"
                    actionListener="#{userGroupSetupController.saveData()}" 
                    update="growl userGroupList userGroupSetupForm" />

Здесь атрибут process = "userGroupSetupForm" является обязательным для вызова Ajax. actionListener вызывает метод из @ViewScope Bean. Также обновляется сообщение рычание, Datatable: userGroupList и Form: userGroupSetupForm.

Раджиб Кумер Гхош
источник
-2
<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>
Кенан Гекбак
источник
Извините, но это по моему скромному мнению совершенно не соответствует действительности. Вы фактически заявляете, что 2 диалога должны быть в их собственной форме, чтобы работать. У вас с уверенностью 99% была другая проблема, которую вы решили и для которой вы теперь думаете, что это решение ...
Kukeltje
Это включенная страница. Возможно, это может вызвать проблемы. Вы должны проверить это до голосования.
Кенан Гекбак
Нет, вы должны были создать минимальный воспроизводимый пример перед публикацией (и только тогда я смогу протестировать) ... И да, включение может привести к проблемам с диалогами и формами, но тогда проблема все еще не в том, что вы, похоже, хотите решить здесь , Ваш первый пример совершенно в порядке, а второй со 100% -ной уверенностью не является решением несуществующей проблемы
Kukeltje
Тем не мение. Мое приложение работает нормально. Я думаю, что не важно, где диалоговые окна в форме. Я должен создать вторую форму, чтобы решить другую проблему.
Кенан Гекбак
Ваше приложение может работать, но это не ясно / не видно из исходной проблемы и вашего решения. Кроме того, вы говорите: «Я думаю, что не важно, где диалоговые окна в форме». Но в вашем ответе кажется важным, где они находятся. Противоречие, которое поддерживает мое утверждение. Извините, но ваш ответ совершенно неверный ... (уже есть еще одно понижение)
Kukeltje