Метод commandButton / commandLink / ajax action / listener не викликається або значення вводу не встановлено / оновлено


345

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

Які можливі причини та рішення для цього?

Відповіді:


687

Вступ

Кожного разу, коли UICommandкомпонент ( <h:commandXxx>, <p:commandXxx>і т. Д.) Не вдається викликати пов'язаний метод дії, або UIInputкомпонент ( <h:inputXxx>, <p:inputXxxx>тощо) не вдається обробити подані значення та / або оновити значення моделей, і ви не бачите жодних винятків, які можна переглянути в Google, та / або попередження в журналі сервера, також не під час налаштування обробника винятків 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компоненти паралельно, але вони не оброблять один одного під час надсилання. Ви також повинні стежити за антипаттерном "God Form"; переконайтеся, що ви ненавмисно не обробляєте / перевіряєте всі інші (невидимі) входи в тій же самій формі (наприклад, приховане діалогове вікно з необхідними входами в тій самій формі). Дивіться також Як користуватися <h: form> на сторінці 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бін (і, таким чином, не в метод getter!), Це повинно виправити це. Дивіться також Як і коли слід завантажувати модель з бази даних для h: dataTable .

  5. Якщо UICommandабо UIInputкомпоненти включені в динамічне джерело, наприклад <ui:include src="#{bean.include}">, то вам потрібно забезпечити збереження точно такого ж #{bean.include}значення протягом часу складання подання запиту на надсилання форми. JSF повторно виконає його під час створення дерева компонентів. Якщо розмістити квасоля в області перегляду та / або переконатися, що ви завантажуєте модель даних в @PostConstructбін (і, таким чином, не в метод getter!), Це повинно виправити це. Дивіться також Як аякс-оновлення динамічного включення вмісту за допомогою навігаційного меню? (JSF SPA) .

  6. renderedАтрибут компонента і всіх його батьків і testатрибут будь-якого батька <c:if>/ <c:when>годі було оцінювати в falseпротягом застосувати запит значень фази підпорядкованої форми запиту. JSF повторно перевірить її як частину гарантії від підроблених / зламаних запитів. Зберігання змінної відповідальності за стан в @ViewScopedквасолі або переконавшись , що ви правильно preinitializing умови в @PostConstructз @RequestScopedквасолі повинні це виправити. Це ж стосується disabledатрибута компонента, який не повинен оцінюватися trueпід час фази значень запиту застосувати. Дивіться також дії JSF CommandButton, не викликані , Форма подання у умовно наданому компоненті не обробляється таh: commandButton не працює, як тільки я оберну його в <h: panelGroup rended> .

  7. onclickАтрибут UICommandкомпонента і onsubmitатрибут UIFormкомпонента не повинен повертати falseабо викликати помилку JavaScript. На консолі JS браузера не повинно бути помилок JS <h:commandLink>або <f:ajax>також не повинно бути помічено. Зазвичай гугл точне повідомлення про помилку вже дасть вам відповідь. Дивіться також Ручне додавання / завантаження jQuery з результатами PrimeFaces у Uncaught TypeErrors .

  8. Якщо ви використовуєте Ajax через JSF 2.x <f:ajax>або, наприклад, PrimeFaces <p:commandXxx>, переконайтеся, що у вас є <h:head>головний шаблон замість <head>. Інакше JSF не зможе автоматично включити необхідні файли JavaScript, які містять функції Ajax. Це призведе до помилки JavaScript типу "мояrra не визначено" або "PrimeFaces не визначено" в консолі JS браузера. Дивіться також h: commandLink actionlistener не викликається, коли використовується з f: ajax та ui: повторити .

  9. Якщо ви використовуєте Ajax, і подані значення закінчуються null, переконайтеся, щоUIInput і UICommandкомпоненти інтересів покриваються <f:ajax execute>або , наприклад <p:commandXxx process>, в іншому випадку вони не будуть виконані / оброблені. Дивіться також Представлені значення форми, не оновлені в моделі при додаванні <f: ajax> до <h: commandButton> та розуміння PrimeFaces процесу / оновлення та JSF f: ajax Execute / render атрибутів .

  10. Якщо подані значення все-таки є null, а ви використовуєте CDI для управління квасолею, тоді переконайтеся, що ви імпортуєте анотацію про обсяг з правильного пакета, інакше CDI за замовчуванням буде @Dependentефективно відтворювати боб при кожній оцінці EL вираз. Дивіться також @SessionScoped квасоля втрачає область застосування і постійно відтворюється, поля стають нульовими і що таке за замовчуванням керований обсяг квасолі в додатку JSF 2?

  11. Якщо заздалегідь надісланий / оновлений батько кнопки <h:form>з UICommandкнопкою за допомогою ajax-запиту, який надходить з іншої форми на тій же сторінці, то перша дія завжди буде невдалою в JSF 2.2 або старішій версії. Друга та наступні дії спрацюють. Це спричинено помилкою в обробці стану перегляду, яка повідомляється як випуск 790 JSF, і наразі фіксується в JSF 2.3. Для старих версій JSF потрібно чітко вказати ідентифікатор<h:form> в renderз <f:ajax>. Дивіться також h: commandButton / h: commandLink не працює при першому натисканні, працює лише при другому клацанні .

  12. Якщо <h:form>було enctype="multipart/form-data"встановлено для того , щоб завантаження файлу підтримки, то вам необхідно переконатися , що ви використовуєте по крайней мере , JSF 2.2, або що сервлет фільтр , який відповідає за аналіз запитів багаточастинні / форм-даних налаштований правильно, в іншому випадку FacesServletволі в кінцевому підсумку не отримує жодних параметрів запиту і, таким чином, не зможе застосувати значення запиту. Налаштування такого фільтра залежить від використовуваного компонента для завантаження файлів. Для Tomahawk <t:inputFileUpload>перевірте цю відповідь, а PrimeFaces <p:fileUpload>- цю відповідь . Або якщо ви насправді взагалі не завантажуєте файл, то видаліть атрибут взагалі.

  13. Переконайтесь, що ActionEventаргумент actionListener- це, javax.faces.event.ActionEventа отже, ні java.awt.event.ActionEvent, що саме більшість ІДЕ пропонують як перший варіант автозаповнення. Не маючи аргументів, також неправильно, якщо ви використовуєте actionListener="#{bean.method}". Якщо ви не хочете аргументувати свій метод, використовуйте actionListener="#{bean.method()}". Або, можливо, ви насправді хочете використовувати actionзамість цього actionListener. Дивіться також Відмінності між дією та 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>. Тому що ці компоненти за замовчуванням перенесені JavaScript на кінець HTML <body>. Отже, якби вони спочатку сиділи всередині a <form>, вони б зараз більше не сиділи в a <form>. Дивіться також p: Дія командної кнопки не працює в діалоговому вікні p:

  17. Помилка в рамках. Наприклад, RichFaces має " помилку перетворення " при використанніrich:calendar елемента інтерфейсу з defaultLabelатрибутом (або, в деяких випадках, rich:placeholderпіделементом). Ця помилка запобігає виклику методу bean, коли для дати календаря не встановлено значення. Відстеження помилок фреймворка можна здійснити, починаючи з простого робочого прикладу та створюючи сторінку назад, доки помилка не буде виявлена.

Підказки про налагодження

Якщо ви все-таки застрягли, настав час налагоджувати. На стороні клієнта натисніть F12 у веб-браузері, щоб відкрити набір інструментів веб-розробників. Перейдіть на вкладку Консоль , щоб побачити коносл JavaScript. Він повинен бути без будь-яких помилок JavaScript. Нижче на екрані - приклад із Chrome, який демонструє випадок подання <f:ajax>увімкненої кнопки, але не <h:head>заявив (як описано у пункті 7 вище).

консоль js

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

мережевий монітор

.

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

налагоджувальний сервер


1
твій другий пункт змусив мене задуматися - надовго. Щойно я з'ясував, що тег f: view в моєму головному файлі був причиною більшості моїх проблем. І, мабуть, тому, що це робить форму, правда?
Пауло Гуедес

2
@pauloguedes Я не можу знайти нічого, що говорить про те, що f: view надає форму. Я розумію, що це просто контейнер. На мій досвід, f: view не відображає жодних елементів.
Лукас

@balusc Невелике уточнення щодо пункту 4, якщо команда Link не в самій DataTable, чи все-таки це має значення?
Лукас

спасибі, суть полягає в тому, що, якщо виправити боб в області перегляду та / або переконатися, що ви завантажуєте модель даних в (пост) конструктор бобу (і, отже, не в методі getter!), слід це виправити.
merveotesi

2
@Kukeltje: це призвело б до винятку EL (вже охоплений першим абзацом у відповіді)
BalusC

54

Якщо ваше h:commandLinkвсередині h:dataTableє, є ще одна причина, чому h:commandLinkможе не працювати:

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

Отже, якщо базове джерело даних має масштабний запит, h:commandLinkвоно не працює!


2
Гаразд, мені це було не зовсім зрозуміло. Я сподіваюся, що моя відповідь все одно корисна, оскільки в моєму випадку я, принаймні, не мав явної справи з UICommand / UIData. "Рішення" просувало підтримку бобів від запиту до обсягу сеансу ...
jbandi

1
Я другий коментар Йенса ... встановлення моєї квасолі 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це одне, що стосується всього, що стосується клієнта. Трохи важко знайти це в Primefacesdoc, але ось одне посилання: developer.am/primefaces/…
akelec

Підказка щодо подання вирішила мою проблему, з якою я стикаюсь цілими днями. Велике спасибі вашому посту!
gpuk360

Дякую, мені приємно. Я навмисно ставлю цю відповідь, тому що у багатьох із нас була така проблема. Я також втратив кілька днів, поки не зрозумів, про що йдеться.
akelec

3

Я сам зациклювався на цьому питанні і знайшов ще одну причину цієї проблеми. Якщо у вашому резервному боці у вас немає методів встановлення властивостей, що використовуються у вашому * .xhtml, дії просто не викликаються.


5
Це повинно було призвести до досить пояснення PropertyNotWritableException. Якщо ви цього не бачили, можливо, ви запустили запит ajax без належного обробника винятків ajax, але ви повинні бачити його в журналах сервера.
BalusC

3
Це виняток не показало, поки я не зробив p: commandButton 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що повертало нулі, які Richface з радістю використовували як ключі рядків. Це завадило моїй <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. Не потрібно писати це як окрему відповідь.
Kukeltje

-1

Це рішення, яке працює для мене.

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

Тут atrribute 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

Все одно. Моя програма працює чудово. Я думаю, що не важливо, де діалогове вікно у формі. Я маю створити другу форму для вирішення іншої проблеми.
Kenan Gökbak

Ваша програма може працювати, але це не зрозуміло / видно з оригінальної проблеми та вашого рішення. Крім того, ви говорите _ "Я думаю, не важливо, де діалогове вікно у формі". _ Але у вашій відповіді, здається, важливо, де вони є. Суперечність, яка підтримує моє твердження. Вибачте, але ваша відповідь явно невірна ... (на це вже є інший результат)
Kukeltje
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.