0

I am goin to explain a problem that I have when I use one composite component inside a template.

Imagine one view like this, that work with a generic managed bean with view scope. I pass it to the template as a parameter.

<?xml version='1.0' encoding='UTF-8' ?> 
<!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:f="http://java.sun.com/jsf/core"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:trkal="http://java.sun.com/jsf/composite/trkalcomponents">

  <ui:composition template="/template.xhtml">
      <ui:param name="maisuBean" value="#{genericBean}" />
  </ui:composition>
</html>

The template is like this. Beside other components, it also use one composite component.

<?xml version='1.0' encoding='UTF-8' ?> 
<!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:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:trkal="http://java.sun.com/jsf/composite/trkalcomponents">

<h:head>
    <title>Titulo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</h:head>

<h:body>
    <h:form enctype="multipart/form-data">
        ...
        <trkal:toolbarbuttonwidget id="buttonToolbar" label="Action" iconName="toolbar.png"
            buttonAction="#{maisuBean.myActionListener}"
            >
        </trkal:toolbarbuttonwidget>
        ...
        <h:commandLink id="otherButton" actionListener="#{maisuBean.myActionListener}">
            <h:graphicImage library="images" name="toolbar.png" />
            <h:outputText value="Other Action" />
        </h:commandLink>
        ...

    </h:form>
</h:body>
</html> 

As you can see, this template use one composite components that allow specify the action listener that hear this event.

<composite:interface>
    <composite:attribute name="id" />
    <composite:attribute name="buttonAction" method-signature="void myAction(javax.faces.event.ActionEvent)" targetAttributeName="actionListener"/>
    <composite:attribute name="iconName" />
    <composite:attribute name="label"/>
    <composite:attribute name="title"/>
    <composite:attribute name="styleClass"/>
</composite:interface>
<composite:implementation>
    <h:outputStylesheet target="head" library="trkalcomponents" name="toolbarbuttonwidget.css"  />
    <h:commandLink id="buttonAction">
        <h:graphicImage library="images" name="#{cc.attrs.iconName}" />
        <h:outputText value="#{cc.attrs.label}" />
    </h:commandLink>
</composite:implementation>

If I click in otherButton, it work fine, but if I click in buttonToolbar it don't work.

09-nov-2012 19:16:28 javax.faces.event.MethodExpressionActionListener processAction
GRAVE: Se ha recibido 'javax.el.PropertyNotFoundException' al invocar la escucha de acción '#{maisuBean.myActionListener}' para el componente 'buttonAction'
09-nov-2012 19:16:28 javax.faces.event.MethodExpressionActionListener processAction
GRAVE: javax.el.PropertyNotFoundException: /template.xhtml @20,6 buttonAction="#{maisuBean.myActionListener}": Propiedad 'myActionListener' no hallada en el tipo com.joxeja.test.ToolBarBean
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:111)

It seem that it can't resolve the EL expression inside the composite component.

What is wrong? How can I use one composite componente inside one template?

I am using Mojarra 2.1.7

Thanks.

Joxeja
  • 43
  • 1
  • 5
  • #{maisuBean.myActionListener}' <--I think this is giving you a pretty big hint. What's the code for your ActionListner? And is the bean registered? – Daniel B. Chapman Nov 09 '12 at 18:41
  • Yes, the bean is registered and as I say it works if I click in otherButton commandLink. The bean is registered as **@ManagedBean(name="genericBean") and @ViewScoped.** – Joxeja Nov 12 '12 at 09:06

1 Answers1

1

Sorry I missed this on the first read:

Your implementation isn't targeting the attributes properly. I made this mistake (as I'm pretty sure all of us do). You need to reference the attributes as -> #{cc.attrs.someAttribute} not by their name. You do this for most of the elements, but not the actionListener. If that is your code it should fix it. Your signatures are correct. You're trying to use the targetAttributeName which I'm not familiar with. My guess is you need to set the id of the component to that name (so your button would be myAction not actionListener (if I'm referencing the same example you are).

That aside, how I would do it is:

    <composite:interface>
    <composite:attribute name="id" />
    <!-- 
    <composite:attribute name="buttonAction" method-signature="void myAction(javax.faces.event.ActionEvent)" targetAttributeName="actionListener"/>
    -->
    <composite:attribute name="buttonAction" method-signature="void action(javax.faces.event.ActionEvent)"/>  
    <composite:attribute name="iconName" />
    <composite:attribute name="label"/>
    <composite:attribute name="title"/>
    <composite:attribute name="styleClass"/>
</composite:interface>
<composite:implementation>
    <h:outputStylesheet target="head" library="trkalcomponents" name="toolbarbuttonwidget.css"  />
        <!-- fix below -->
        <h:commandLink id="buttonAction" actionListener=#{cc.attrs.buttonAction}>
            <h:graphicImage library="images" name="#{cc.attrs.iconName}" />
            <h:outputText value="#{cc.attrs.label}" />
        </h:commandLink>
    </composite:implementation>

I like this method because it is similar to the rest of the way pages are marked up and it seems simple. Give it a shot.

Daniel B. Chapman
  • 4,647
  • 32
  • 42
  • Many thanks for the help, but I had tried this way and the result is the same. The error message is that it can't found the property **myActionListener** of the managed bean **genericBean**. It like as it try call to getter method for this property, and logically it doesn't exist. – Joxeja Nov 13 '12 at 10:39
  • To confirm: if you do -> `` in the form it works? Your error sounds like it doesn't work at all, not that it doesn't work inside the component. – Daniel B. Chapman Nov 13 '12 at 16:59
  • Yes, the commandLink **otherButton** of the template works fine, but the toolbarbuttonwidget **buttonToolbar** of the teamplate don't work. One big detail. I can't put **genericBean**.myActionListener because the template manage the bean **maisuBean**. The template receive the reference of the bean as a parameter. There are some level: use page, template and composite componente, every one manage its bean, that receive or pass as parameter. In each level I can use its reference. The problem given in the composite componente that can't resolve the EL expression for the listener method. – Joxeja Nov 14 '12 at 07:18