5

In the given case, I want to use a facelet with different ManagedBeans, so the regarding action-bean is given as an 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:ui="http://java.sun.com/jsf/facelets" 
    xmlns:h="http://java.sun.com/jsf/html" >
<h:body>
    <ui:include src="ratings.xhtml" >
      <ui:param name="createAction" value="#{myOneCreateAction}" />
      <ui:param name="ratings" value="#{context.ratings}" />
    </ui:include>
</h:body>
</html>

I'm giving the create action as parameter value="#{myOneCreateAction}".

Within that facelet is a component also being used several times on other pages - so I try to refactor it in a composite component.

<html xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:ui="http://java.sun.com/jsf/facelets" 
  xmlns:h="http://java.sun.com/jsf/html" 
  xmlns:f="http://java.sun.com/jsf/core" 
  xmlns:io="http://java.sun.com/jsf/composite/inoutComponents">
<ui:composition>
    <rich:dataTable id="ratingTblId" 
    value="#{ratings}" 
    var="rating">
        <rich:column>
             <io:removeButton
                 id="removeButton"
                 actionMethod="#{createAction.removeRating}"
                 immediate="true"
                 render=":#{rich:clientId('ratingTblId')}" />

             <h:commandButton
                 id="removeButton2"
                 actionListener="#{createAction.removeRating}"
                 immediate="true" >                    
                    <f:ajax render="ratingTblId" />
              </h:commandButton>
        </rich:column>
</rich:dataTable>
</ui:composition>
</html>

See, how the method is given as actionMethod="#{createAction.removeRating}" to the component. This component itself looks like following:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:cc="http://java.sun.com/jsf/composite">
    <!-- INTERFACE -->
    <cc:interface>
        <cc:attribute 
            name="actionMethod" 
            targets="remove" 
            method-signature="void f(javax.faces.event.ActionEvent)"/>
        <cc:attribute name="render" required="false" />
    </cc:interface>

    <!-- IMPLEMENTATION -->
    <cc:implementation> 
        <h:commandButton 
           id="remove"
           actionListener="#{cc.attrs.actionMethod}" 
           onclick="if (!confirm('Do you really?')) { return false; }">
           <f:ajax execute="@this" render="#{cc.attrs.render}" />
        </h:commandButton> 
    </cc:implementation>
</ui:composition>

and last but not least, the managed bean

Name("myOneCreateAction")
@Scope(ScopeType.CONVERSATION)
public class MyOneCreateAction {
   ...
   public void removeRating(ActionEvent ev) {
        // do something
   }
   ...
}

Surprisingly, while the removeButton2 correctly jumps into the right function, the composite components version returns a

javax.faces.event.AbortProcessingException: Target Unreachable, 
      identifier 'createAction' resolved to null

instead. Am using Mojarra JSF 2.1.26 with Seam 2.3.1.CR1. There are no nested composite components. When replacing the composite component parameter to #{myOneCreateAction.removeRating}, it works like expected.

Has anybody seen this before? Am I blind? Any work-arounds known... ? Thanks in advance!

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
L-Ray
  • 1,637
  • 1
  • 16
  • 29
  • Well explained and composed. Well done for first hit ;-) Did you have a look at [that](http://stackoverflow.com/a/3707809/1199132), by the way? – Aritz Nov 26 '13 at 16:45
  • Hi @XtremeBiker, and thnx for the positive feedback. Well, yeah, used that as ressource before writing this question. Debugged the whole method and would expect to at least jump into it. But nope, didn't happen. :-( – L-Ray Nov 27 '13 at 21:39

2 Answers2

1

As a work-around I rewrote the component to give action bean and action method as two separate parameters resolving them as following

xhtml:

<io:removeButton
             id="removeButton"
             actionBean="#{createAction}"
             actionMethod="removeRating"
             immediate="true"
             render=":#{rich:clientId('ratingTblId')}" />

composite component:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:cc="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<cc:interface>
    <cc:attribute name="actionBean" />
    <cc:attribute name="actionMethod" />
    <cc:attribute name="render" required="false" />
</cc:interface>

<!-- IMPLEMENTATION -->
<cc:implementation> 
    <h:commandButton 
       id="remove"
       action="#{cc.attrs.actionBean[cc.attrs.actionMethod]}" 
       onclick="if (!confirm('Do you really?')) { return false; }">
       <f:ajax execute="@this" render="#{cc.attrs.render}" />
    </h:commandButton> 
</cc:implementation>
</ui:composition>

also changing the action methods signature to return String instead of void. That does not look that super sexy anymore, but works. :-/

L-Ray
  • 1,637
  • 1
  • 16
  • 29
1

I was having the same issue, found out that it has been fixed on version 2.2.15: https://github.com/javaserverfaces/mojarra/issues/4271

qxlab
  • 1,506
  • 4
  • 20
  • 48