Могу ли я сообщить JSF, что атрибут f: применяется к некоторой части моего составного компонента? - PullRequest
1 голос
/ 02 марта 2012

В следующем примере я могу как-то сказать JSF, что <f:attribute> применяется к какому-то конкретному компоненту, так же, как я могу использовать for="..." в <f:convertNumber for="..."> и <f:validator for="...">?

<mytags:myCcInputWithValueHolder id="myparent" item="#{myBean.myDouble}" >
    <f:convertNumber minFractionDigits="2" for="myinput"/>
    <f:validator validatorId="bindableDoubleRangeValidator" for="myinput"/>
    <f:attribute name="minimum" value="#{30.00}"/>
    <f:attribute name="maximum" value="#{39.99}"/>
</mytags:myCcInputWithValueHolder>


Справочная информация:

Следуя решению BalusC для решения проблемы JSF , я использую специальный валидатор. Чтобы скорректировать этот валидатор некоторыми параметрами, используется <f:attribute>.

Далее, при использовании составного компонента с EditableValueHolder я могу (фактически: must ) назначить валидатору фактический h:inputText. Но я не могу сделать то же самое для f:attribute s, поэтому они добавляются в вызывающий родительский компонент. Например:

<composite:attribute name="item" .../>
<composite:editableValueHolder name="myinput" targets="myinputtext"/>        
:
<h:inputText id="myinputtext" value="#{cc.attrs.item}">
    <!-- <composite:insertChildren /> doesn't change anything -->
</h:inputText>

... используется с <f:validator for="myinput" ...>, как показано в верхней части этого поста, привязывает валидатор к myparent:myinputtext, но атрибуты связаны с myparent.


Обходные:

Документация для <f:attribute> действительно гласит :

Добавить атрибут к UIComponent, связанный с пользовательским действием ближайшего родительского UIComponent.

И учитывая, что следующий составной компонент также работает как ожидалось:

<composite:attribute name="item" .../>
<composite:attribute name="min" .../>
<composite:attribute name="max" .../>
:
<h:inputText id="myinput" value="#{cc.attrs.item}">
    <f:convertNumber minFractionDigits="2"/>
    <f:validator validatorId="bindableDoubleRangeValidator"/>
    <f:attribute name="minimum" value="#{cc.attrs.min}"/>
    <f:attribute name="maximum" value="#{cc.attrs.max}"/>
</h:inputText>

... с

<mytags:myCcInputWithValidator 
   item="#{myBean.myDouble}" min="#{30.00}" max="#{39.99}"/>

Кроме того, я могу легко расширить BindableDoubleRangeValidator от BalusC , чтобы перейти в родительские компоненты для получения значения:

Object getAttribute(FacesContext c, UIComponent component, String name) {
    Object result = component.getAttributes().get(name);
    if (result == null && component.getParent() != null) {
        result = getAttribute(c, component.getParent(), name);
    }
    return result;
}

Тем не менее: есть ли лучшее решение?

1 Ответ

3 голосов
/ 05 марта 2012

Это действительно противно.<f:attribute> действительно относится к ближайшему родителю UIComponent.Если вы вложите его в составной компонент, то это будет характерно для самого составного компонента.Одним из способов было бы просто скопировать атрибуты из композита в рассматриваемый компонент ввода:

<h:inputText id="myinputtext" value="#{cc.attrs.item}">
    <f:attribute name="minimum" value="#{cc.attrs.minimum}"/>
    <f:attribute name="maximum" value="#{cc.attrs.maximum}"/>
</h:inputText>

, чтобы первый фрагмент кода в вашем вопросе работал.

Что касается вашего последнегофрагмент кода, проще было бы получить родительский составной компонент вместо UIComponent#getCompositeComponentParent().

Object getCompositeParentAttribute(UIComponent component, String name) {
    UIComponent composite = UIComponent.getCompositeComponentParent(component);
    return composite.getAttributes().get(name);
}

В конце концов, я бы просто выбрал новый составной, если необходимо, используятот же шаблон, что и исходный композит с помощью <ui:decorate>.Композиты предназначены для минимизации повторяющихся шаблонов.

<my:inputDouble value="..." min="..." max="..." />

с

<cc:implementation>
    <ui:decorate template="/WEB-INF/templates/someCommonTemplate.xhtml">
        <ui:define name="input">
            <h:inputText id="myinput" value="#{cc.attrs.value}">
                <f:convertNumber minFractionDigits="2" />
                <f:validator validatorId="bindableDoubleRangeValidator"/>
                <f:attribute name="minimum" value="#{cc.attrs.min}"/>
                <f:attribute name="maximum" value="#{cc.attrs.max}"/>
            </h:inputText>
        </ui:define>
    </ui:decorate>
</cc:implementation>
...