title: JSF 2 -- Composite component with optional listener attribute on f:ajax
body: <p>I have a composite component that looks something like this:</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html 
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:dm="http://davemaple.com/dm-taglib"
      xmlns:rich="http://richfaces.org/rich"
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:fn="http://java.sun.com/jsp/jstl/functions"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:a4j="http://richfaces.org/a4j"&gt;
  
  &lt;cc:interface&gt;
      &lt;cc:attribute name="styleClass" /&gt;
      &lt;cc:attribute name="textBoxStyleClass" /&gt;
      &lt;cc:attribute name="inputTextId" /&gt;
      &lt;cc:attribute name="labelText" /&gt;
      &lt;cc:attribute name="tabindex" /&gt;
      &lt;cc:attribute name="required" default="false" /&gt;
      &lt;cc:attribute name="requiredMessage" /&gt;
      &lt;cc:attribute name="validatorId" /&gt;
      &lt;cc:attribute name="converterId" /&gt;
      &lt;cc:attribute name="title"/&gt;
      &lt;cc:attribute name="style"/&gt;
      &lt;cc:attribute name="unicodeSupport" default="false"/&gt;
      &lt;cc:attribute name="tooltip" default="false"/&gt;
      &lt;cc:attribute name="tooltipText" default=""/&gt;    
      &lt;cc:attribute name="tooltipText" default=""/&gt;
      &lt;cc:attribute name="onfail" default=""/&gt;
      &lt;cc:attribute name="onpass" default=""/&gt;
  &lt;/cc:interface&gt;
  
  &lt;cc:implementation&gt;
  
          &lt;ui:param name="converterId" value="#{! empty cc.attrs.converterId ? cc.attrs.converterId : 'universalConverter'}" /&gt;
          &lt;ui:param name="validatorId" value="#{! empty cc.attrs.validatorId ? cc.attrs.validatorId : 'universalValidator'}" /&gt;
          &lt;ui:param name="component" value="#{formFieldBean.getComponent(cc.attrs.inputTextId)}" /&gt;
          &lt;ui:param name="componentValid" value="#{((facesContext.maximumSeverity == null and empty component.valid) or component.valid) ? true : false}" /&gt;
          &lt;ui:param name="requiredMessage" value="#{! empty cc.attrs.requiredMessage ? cc.attrs.requiredMessage : msg['validation.generic.requiredMessage']}" /&gt;
          &lt;ui:param name="clientIdEscaped" value="#{fn:replace(cc.clientId, ':', '\\\\\\\\:')}" /&gt;
  
          &lt;h:panelGroup layout="block" id="#{cc.attrs.inputTextId}ValidPanel" style="display:none;"&gt;
              &lt;input type="hidden" id="#{cc.attrs.inputTextId}Valid" value="#{componentValid}" /&gt;
          &lt;/h:panelGroup&gt;
  
          &lt;dm:outputLabel for="#{cc.clientId}:#{cc.attrs.inputTextId}" id="#{cc.attrs.inputTextId}Label"&gt;#{cc.attrs.labelText}&lt;/dm:outputLabel&gt;
          &lt;dm:inputText 
              styleClass="#{cc.attrs.textBoxStyleClass}"
                 tabindex="#{cc.attrs.tabindex}"
                 id="#{cc.attrs.inputTextId}"
                 required="#{cc.attrs.required}"
                 requiredMessage="#{requiredMessage}"
                 title="#{cc.attrs.title}"
                 unicodeSupport="#{cc.attrs.unicodeSupport}"&gt;
              &lt;f:validator validatorId="#{validatorId}" /&gt;
              &lt;f:converter converterId="#{converterId}" /&gt;
              &lt;cc:insertChildren /&gt;
              &lt;f:ajax 
                  event="blur" 
                  execute="@this" 
                  render="#{cc.attrs.inputTextId}ValidPanel #{cc.attrs.inputTextId}Msg" 
                  onevent="on#{cc.attrs.inputTextId}Event" /&gt;
          &lt;/dm:inputText&gt;
          &lt;rich:message for="#{cc.clientId}:#{cc.attrs.inputTextId}" id="#{cc.attrs.inputTextId}Msg" style="display: none;" /&gt;
          &lt;script&gt;
              function on#{cc.attrs.inputTextId}Event(e) {
                  if(e.status == 'success') {
                      $('##{clientIdEscaped}\\:#{cc.attrs.inputTextId}').trigger($('##{cc.attrs.inputTextId}Valid').val()=='true'?'pass':'fail');
                  }
              }
              $('##{clientIdEscaped}\\:#{cc.attrs.inputTextId}').bind('fail', function() {
                  $('##{clientIdEscaped}\\:#{cc.attrs.inputTextId}, ##{clientIdEscaped}\\:#{cc.attrs.inputTextId}Label, ##{cc.attrs.inputTextId}Msg, ##{cc.id}Msg').addClass('error');
                  $('##{cc.id}Msg').html($('##{clientIdEscaped}\\:#{cc.attrs.inputTextId}Msg').html());
                  #{cc.attrs.onfail}
              }).bind('pass', function() {
                  $('##{clientIdEscaped}\\:#{cc.attrs.inputTextId}, ##{clientIdEscaped}\\:#{cc.attrs.inputTextId}Label, ##{cc.attrs.inputTextId}Msg, ##{cc.id}Msg').removeClass('error');
                  $('##{cc.id}Msg').html($('##{clientIdEscaped}\\:#{cc.attrs.inputTextId}Msg').html());
                  #{cc.attrs.onpass}
              });
          &lt;/script&gt;
          &lt;a4j:region rendered="#{facesContext.maximumSeverity != null and !componentValid}"&gt;
              &lt;script&gt;
                  $(document).ready(function() { 
                      $('##{clientIdEscaped}\\:#{cc.attrs.inputTextId}').trigger('fail');
                  });
              &lt;/script&gt;
          &lt;/a4j:region&gt;
  &lt;/cc:implementation&gt;
  
  &lt;/html&gt;
  </code></pre>
  
  <p>I'd like to be able to add an optional "listener" attribute which if defined would add an event listener to my f:ajax but I'm having trouble figuring out how to accomplish this. Any help would be appreciated.</p>