#{cc.clientId} оценивается в неправильном композите после обновления до JSF 2.2
У меня есть библиотека тегов, которая была написана в JSF 2.0 + PrimeFaces 3.4, сейчас я пытаюсь обновить до JSF 2.2 и PrimeFaces 4.0. Но я понял, что значение атрибутов, переданных компоненту, оценивается в составном компоненте, и это приводит к неверному идентификатору для рендеринга.
enum.xhtml (составной компонент)
<cc:interface>
<cc:attribute name="render" default="@this"/>
.....
</cc:interface>
<cc:implementation>
<h:selectOneMenu ......../>
<p:ajax update="#{cc.attrs.render}" process="#{cc.attrs.execute}" />
</cc:implementation>
использование:
<t:enum id="authenticationSource" value="#{authenticationStrategy}" .....
render=":#{cc.clientId}:tabView:passwordVisibility"/>
значение атрибута рендеринга, которое :#{cc.clientId}:tabView:passwordVisibility
, должно быть
:j_idt1:j_idt3:j_idt5:editorDialog:j_idt39:j_idt40:tabView:passwordVisibility`
Но это оценивается как
:j_idt1:j_idt3:j_idt5:editorDialog:j_idt39:j_idt40:tabView:autheticationSource:tabView:passwordVisibility
Значение атрибута рендера оценивается в составном компоненте, что приводит к ошибке. Следует оценить, где он используется, и это было так в JSF 2.0. Есть ли свойство конфигурации или что-нибудь, чтобы преодолеть эту ошибку.
Я использую wildfly 8.1.0-Final
1 ответ
Этот композит неправильно спроектирован. Вы не должны использовать #{cc.clientId}
вне контекста композита. В целом, вы не должны ничего знать о внутренних компонентах композита вне композита. Сам композит должен беспокоиться об этом.
Эта конструкция потерпит неудачу, если вы вложите составные компоненты друг в друга. #{cc}
тогда фактически ссылался бы на "текущий" составной компонент. Возможно, вы полагались на ошибку в более старой реализации JSF, где #{cc}
область не очищается должным образом после вложенного составного компонента (то есть она будет ссылаться на последнее назначенное значение вместо значения, доступного в текущем контексте).
Возможно, вы стали жертвой чрезмерного использования составных компонентов только для неправильной установки и только из-за природы нулевой конфигурации по сравнению с обычными файлами тегов / включениями. Для получения подробной информации о том, когда именно использовать тот или иной, обратитесь к разделу Когда использовать
Если вы абсолютно уверены, что композит является правильным решением для ваших требований, и / или вы соответствующим образом реорганизовали композит, чтобы исключить упомянутое неправильное использование, тогда есть 2 возможных подхода для применения поведения клиента к составному компоненту, в зависимости от конкретное функциональное требование (вы можете даже объединить оба пути, если необходимо).
Если вы хотите, чтобы композитный ajax-рендеринг компонента находился вне композита, externalize
<p:ajax>
(или же<f:ajax>
) как<cc:clientBehavior>
:<cc:interface> <cc:clientBehavior name="myCustomEventName" targets="idOfTargetComponent" event="valueChange" /> ... </cc:interface> <cc:implementation> <h:selectOneMenu id="idOfTargetComponent" ...> <f:selectItems ... /> </h:selectOneMenu> </cc:implementation>
Который должен использоваться как:
<t:enum ...> <p:ajax event="myCustomEventName" update=":absoluteClientIdOfComponentOUTSIDEComposite" /> </t:enum> <x:someComponent id="idOfComponentOUTSIDEComposite" />
Если вы хотите, чтобы композит ajax-рендерил компонент внутри композита, то пусть композит делает все это сам.
<cc:interface> ... </cc:interface> <cc:implementation> <h:selectOneMenu ...> <f:selectItems ... /> <p:ajax update="idOfComponentINSIDEComposite" /> </h:selectOneMenu> <x:someComponent id="idOfComponentINSIDEComposite" /> </cc:implementation>
И использовать его обычным способом:
<t:enum ... />