#{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 возможных подхода для применения поведения клиента к составному компоненту, в зависимости от конкретное функциональное требование (вы можете даже объединить оба пути, если необходимо).

  1. Если вы хотите, чтобы композитный 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" />
    
  2. Если вы хотите, чтобы композит 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 ... />
    
Другие вопросы по тегам