How to attach ajax event to composite component?

Ronald picture Ronald · Aug 10, 2015 · Viewed 9.4k times · Source

I have the following composite component (<v2:inputText2>)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich">

<!-- INTERFACE -->
<composite:interface>
    <composite:attribute name="baseId" required="true" />
    <composite:attribute name="size" required="true" />
    <composite:attribute name="value" required="true" />
  <composite:attribute name="align" required="false" default="" />
  <composite:attribute name="label" required="false" default="" />
  <composite:attribute name="labelStyle" required="false" default="" />
    <composite:attribute name="disabled" required="false" default="false" />
    <composite:attribute name="required" required="false" default="false" />
    <composite:attribute name="inputStyle" required="false" default="" />
    <composite:editableValueHolder name="inTxt" />
</composite:interface>

<!-- IMPLEMENTATION -->
<composite:implementation>
    <h:panelGroup id="#{cc.attrs.baseId}Dec">
        <table class="decTable" style="align:#{cc.attrs.align};" border="1">
            <tr>
                <td class="labelSize" style="vertical-align: middle;">
                  <h:outputLabel
                        id="#{cc.attrs.baseId}Lbl" for="#{cc.attrs.baseId}"
                        value="#{cc.attrs.label}" style="#{cc.attrs.labelStyle}" /></td>

                <td width="#{cc.attrs.size}">
                  <h:inputText
                        id="inTxt" value="#{cc.attrs.value}"
                        disabled="#{cc.attrs.disabled}"
                        style="width: 99%; #{cc.attrs.inputStyle}"
                        required="#{cc.attrs.required}">
                        <!-- composite:insertChildren / -->
                    </h:inputText></td>
            </tr>

            <tr>
                <td colspan="2"><h:panelGroup id="#{cc.attrs.baseId}Error">
                        <rich:message for="#{cc.attrs.baseid}">
                            <rich:tooltip id="#{cc.attrs.baseId}TT" styleClass="validError">
                                <rich:message id="#{cc.attrs.baseId}TTMsg"
                                    for="#{cc.attrs.baseId}" showDetail="false" showSummary="true" />
                            </rich:tooltip>
                        </rich:message>
                    </h:panelGroup></td>
            </tr>
        </table>
    </h:panelGroup>
</composite:implementation>

</html>

In the following Fragment, I want to add an <a4j:ajax> event to this component using like this:

    <rich:panel style="width:560px;">
        <f:facet name="header">
            <h:outputText value="Combobox "></h:outputText>
        </f:facet>
        <v2:inputText2 size="300px" baseId="baseId_txt" id="txt" label="Text:"
            value="#{testInput2.value}">
            <a4j:ajax event="change" render="dbgText"/>
        </v2:inputText2>

        <h:outputText value="#{testInput2.value}" id="dbgText"/>
    </rich:panel>
    <aj4:commandButton id="cmdOK" value="Ok"
        action="#{testInput2.cmdOk ()}" render="@form" />

When I call the Testpage, then I get the following Error:

testInput2.xhtml @23,48 <a4j:ajax> Error: enclosing composite component does not support event change

How can I solve the problem?

The Ajax-Event should trigger a UI-Bean-Methode.

Thanks Ronald

Answer

BalusC picture BalusC · Aug 10, 2015

You need to register it as client behavior in composite's interface.

<cc:interface>
    ...
    <cc:clientBehavior name="clientEvent" targets="inputId" event="valueChange" />
</cc:interface>
<cc:implementation>
    ...
    <h:inputText id="inputId" ... />
</cc:implementation>
  • name: The custom event name as you would specify in composite's client. Can be the same as the actual event name. Can be a customized one. It's all free to your choice.
  • targets: The composite implementation relative client ID of the target component on which the actual client behavior should be attached.
  • event: The actual event name which the actual client behavior should be listening. Note that the default event of EditableValueHolder components is valueChange and not change. You can for text input fields keep using change if you want.

With the above declaration example, you can use it in template client as below:

<my:composite ...>
    <f:ajax event="clientEvent" ... />
</my:composite>

After this, you'll face a second but unrelated problem which is already asked and answered here: <f:ajax render> not working via <composite:clientBehavior>.


Unrelated to the concrete problem, that composite can better be a tagfile. And, that HTML table markup is not Web 2.0.