UIForm с prependId = "false" breaks <f: ajax render>

У меня возник вопрос о том, что только тот факт, что только UIForm получил атрибут prependId. Почему атрибут не указан в интерфейсе NamingContainer? Теперь вы, вероятно, скажете, что из-за обратной совместимости, но я бы предпочел бы нарушить компиляцию и позволить пользователям, которые реализуют этот интерфейс, также реализовать методы для prependId.

Основная проблема с моей точки зрения относительно prependId в компоненте UIForm заключается в том, что она сломается findComponent() Я ожидал бы, что если я использую prependId, тогда поведение NamingContainer изменилось бы, не только относящееся к рендерингу, но также и при поиске компонентов в дереве компонентов.

Вот простой пример:

<h:form id="test" prependId="false">
  <h:panelGroup id="group"/>
</h:form>

Теперь, когда я хочу получить компонент panelGroup, я ожидал бы передать строку "group" методу findComponent(), но он ничего не найдет, вместо этого я должен использовать "test:group".

Конкретная проблема с этим заключается в использовании ajax с prependId="false". Тег ajax ожидает в обновлении и обработке атрибутов, что ценности заботятся об именовании контейнеров. Немного странно, что, когда я использую prependId="false", я должен указать полный идентификатор или путь, но хорошо.

<h:form id="test" prependId="false">
  <h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
  <h:commandButton value="go">
    <f:ajax render="test:group"/>
  </h:commandButton>
</h:form>

Ну, этот код будет отображаться без проблем, но он не будет обновлять panelGroup, потому что он не может его найти. PartialViewContext будет содержать только id "group" как элемент renderIds. Я не знаю, ожидалось ли это, возможно, но я не знаю кода. Теперь мы переходим к точке, где метод findComponent() не может найти компонент, потому что выражение, переданное как параметр, "group", где метод ожидает, что "test:group" найдет компонент.

Одним из решений является написать собственный findComponent(), который я выбрал для решения этой проблемы. В этом методе я обрабатываю компонент, который является NamingContainer и имеет свойство prependId, установленное как false, как обычный UIComponent. Мне нужно будет сделать это для каждого UIComponent, который предлагает атрибут prependId, и это плохо. Отражение поможет обойти статическое определение типов, но это еще не очень чистое решение.

Другой способ - ввести атрибут prependId в интерфейсе NamingContainer и изменить поведение findComponent() для работы, как описано выше.

Последнее предлагаемое решение изменило бы поведение тега ajax, чтобы передать весь идентификатор, но это разрешило бы только проблему ajax, а не программные проблемы реализации findComponent().

Что вы думаете об этом и почему, черт возьми, это реализовано так? Я не могу быть первым с этой проблемой, но мне не удалось найти связанные темы?!

Ответы

Ответ 1

Действительно, UIComponent#findComponent(), как сделано <f:ajax render>, не работает при использовании <h:form prependId="false">. Эта проблема известна и является "не исправлена": Спецификация спецификации JSF 573.

По моему скромному мнению, они никогда не должны добавлять атрибут prependId к UIForm во время JSF 1.2. Просто было сделано для того, чтобы поддерживать j_security_check пользователей счастливыми, которые хотели бы использовать форму JSF с входными компонентами JSF для этого (j_security_check требует точных имен полей ввода j_username и j_password, которые не могут быть изменены с помощью конфигурации), Но они точно не поняли, что во время JSF 1.2 было добавлено еще одно усовершенствование, которое позволяет вам просто использовать <form> для этого вместо того, чтобы придерживаться <h:form>. И затем пуристы CSS/jQuery начинают злоупотреблять prependId="false", чтобы избежать экранирования символа разделителя : в их слабо выбранных селекторах CSS.

Просто не используйте prependId="false", когда-либо.

Для j_security_check просто используйте <form> или новый сервлет 3.0 HttpServletRequest#login(). См. Также Выполнение аутентификации пользователей в Java EE/JSF с помощью j_security_check.

Для селекторов CSS, если вам абсолютно необходим селектор идентификаторов (и, следовательно, не более многоразовый селектор классов), просто оберните интересующий компонент простым HTML <div> или <span>.

См. также: