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.

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


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он не работает!


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!)


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".

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


это была моя главная проблема на одной из наших страниц, ни один из пунктов в принятом ответе не приблизил нас, где вы нашли эту информацию?
— Уриэль Арвизу

Ну, у меня была эта проблема много раз, и я провел исследование и обнаружил, что он p:commandButtonимеет несколько значений typeатрибута и buttonотносится ко всему на стороне клиента. Это немного трудно найти это в Primefacesдок, но вот одна ссылка: developer.am/primefaces/...
— akelec

Ваша подсказка подсказки решила мою проблему, с которой я сталкиваюсь уже несколько дней. Большое спасибо за ваш пост!
— gpuk360

Спасибо, это мое удовольствие. Я сознательно поставил этот ответ, потому что у многих из нас была такая проблема. Я тоже потерял несколько дней, пока не понял, о чем идет речь.
— akelec

3

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


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


1

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



-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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.