# {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"/>

Значение атрибута render, которое :#{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} не удаляется должным образом после вложенного составного компонента (т.е. она будет ссылаться на последнее назначенное значение вместо значения, доступного в текущем контексте).

Возможно, вы являетесь жертвой злоупотребления составными компонентами только для неправильного использования и только из-за нулевой конфигурации по сравнению с обычными файлами tagfiles/includes. Для подробностей относительно того, когда именно использовать тот или иной, перейдите в Когда использовать < ui: include > , файлы тегов, составные компоненты и/или настраиваемые компоненты? По существу, используйте только композит и только если вы хотите привязать связку тесно связанных компонентов к свойству single bean и, следовательно, конечно, не к "целому" bean с несколькими свойства.

Если вы абсолютно уверены, что композит является правильным решением для вашего требования и/или вы реорганизовали композит, чтобы устранить упомянутое злоупотребление, тогда есть два возможных подхода для применения поведения клиента в составном компоненте, в зависимости от конкретного функционального требования (при необходимости вы можете комбинировать оба пути).

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