1

I need a method to be executed whenever my component gets rendered, i.e. when it gets created for the first time and on every update.

A way of doing it is using f:metadata and f:event for the event "preRenderComponent". It works perfectly well, unless I also have a f:metadata with f:viewParam in the view holding the component. If I have a f:viewParam in the parent view, f:event, in the component, gets ignored.

How to solve this problem, why does it happen?

Here's some code to reproduce the problem:

The view (index.xhtml):

<h:body>
  <f:metadata>
    <f:viewParam name="vparam" value="#{index.vparam}" />
  </f:metadata>

  <comp:component />
</h:body>

The managedBean (Index.java)

@ManagedBean(name="index")
public class Index implements Serializable {
    private String vparam;

    public void setVparam(String vparam) {
        this.vparam = vparam;
    }

    public String getVparam() {
        return vparam;
    }
}

The component view (component.xhtml):

<h:body>
    <composite:interface componentType="component" />
    <composite:implementation>
        <f:metadata>
            <f:event type="preRenderComponent" listener="#{cc.generateString}" />
        </f:metadata>
        <h:outputText value="#{cc.string}" />
    </composite:implementation>
</h:body>

The component's java class (Component.java):

@FacesComponent(value="component")
public class Component extends UINamingContainer implements Serializable {
    private String string;

    public void generateString(){
        System.out.println("*** PRE RENDERING COMPONENT...");
        System.out.flush();
        string = "It worked!";
    }

    public String getString(){
        return string;
    }
}

The expected output of this code is: the string "It worked!" printed in the index page. The actual output is: nothing, since a null string is printed as "" by the h:outputText.

In the log file, "*** PRE RENDERING COMPONENT..." is not printed, it's never executed.

If I remove the following line from index.xhtml, everything works fine:

<f:viewParam name="vparam" value="#{index.vparam}" />

Why does the presence of "viewParam" in the component's parent page makes JSF to ignore "f:event" in the component?

Thanks in advance for any answer.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
Tiago Peres França
  • 2,537
  • 2
  • 18
  • 22

1 Answers1

2

As per the <f:metadata> documentation, the view can have only one <f:metadata> which needs to go in template client (the top level XHTML page which is been opened upon HTTP request).

The <f:metadata> in the composite is displaced. It doesn't belong there. Get rid of it. The <f:event> does by itself not require to be placed inside <f:metadata>. This works as intented:

<composite:implementation>
    <f:event type="preRenderComponent" listener="#{cc.generateString}" />
    ...
</composite:implementation>

Your concrete problem is caused because the second <f:metadata> is ignored altogether including all of its children.

True, you're seeing a lot of <f:metadata><f:viewParam><f:event type="preRenderView"> examples, but the <f:event> is in this specific case actually a workaround and just for self-documentary purposes placed inside the very same <f:metadata> as the <f:viewParam>s it needs to work with. In JSF 2.2, the right way has been introduced in flavor of <f:viewAction>. See also What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • Thank you very much for the answer! Since I don't intend to upgrade to JSF 2.2 for now, I used the f:event outside f:metadata, it's working fine now ;) – Tiago Peres França Jun 27 '13 at 17:34