How to retrieve value of a ui:param in the backing

2019-03-14 07:47发布

I'm passing a parameter p1 to another page page.xhtml:

<ui:include src="page.xhtml">
    <ui:param name="p1" value="#{someObject}"/>
</ui:include>

Is this possible to evaluate #{p1} inside @PostConstruct method of the backing bean of page.xhtml? Using the following piece of code, #{p1} cannot resolve:

FacesContext currentInstance = FacesContext.getCurrentInstance();
currentInstance.getApplication().evaluateExpressionGet(currentInstance, "#{p1}", String.class);

Why do I need this?

I'm using an xhtml file (say component.xhtml) as a custom UI component. This file has a backing bean from which I should get component data. Since I'm including this xhtml file twice or more in my main JSF page, I want to pass different objects to each of component.xhtml so that my component work with my custom data each time included.

3条回答
别忘想泡老子
2楼-- · 2019-03-14 07:50

The param is not available in the @PostConstruct method; you can use the preRenderComponent event to initialize the parameters inside your backing bean; just put it after the ui:composition of the included page, it will be executed before the rendering of the included page itself.

Following the OP example of a passing a p1 parameter to a page.xhtml template

the main page:

<ui:include src="page.xhtml">
    <ui:param name="p1" value="#{someObject}"/>
</ui:include>

page.xhtml:

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

<ui:composition>
    <f:event listener="#{backingBean.init(p1)}" type="preRenderComponent"/>
        ...

</ui:composition>

</html>

BackingBean.java:

@ViewScoped
 public class BackingBean{

     private Object p1;
     public void init(Object value){        
     this.p1=p1;
    }

    ...
 }

the event is fired before the render of the ui:composition tag, that is before the render of page.xhtml

查看更多
smile是对你的礼貌
3楼-- · 2019-03-14 07:51

This works for me:

<ui:include src="page.xhtml">
     <ui:param name="p1" value="#{someObject}"/>
</ui:include>

page.xhtml:

<c:set var="data" value="#{p1}" scope="request"/>

Your bean:

@ViewScoped
public class ManagedBean{

     private Object someObject;

     public Object getSomeObject(){
         if(someObject== null){
            HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
            someObject= request.getAttribute("data");
          }
          return someObject;
     }

     public void setSomeObject(Object someObject){
          this.someObject = someObject;
     }}
查看更多
Emotional °昔
4楼-- · 2019-03-14 08:13

In Mojarra, you can get it as an attribute of the FaceletContext. You can get it in the @PostConstruct of a managed bean which is guaranteed to be referenced/constructed for the first time in the included page (and thus not in the parent page before the <ui:param> is declared in the component tree).

FaceletContext faceletContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
Object p1 = faceletContext.getAttribute("p1");

In MyFaces, the whole FaceletContext isn't available in managed beans as it's discarded by end of view build time and this construct would then not work. To be JSF implementation independent, you might want to consider to set it via <c:set scope="request"> instead. It's then available as a request attribute.

As to the concrete functional requirement, consider creating a comoposite component with a backing component. For some examples, see our composite component wiki page and this blog about using multiple input components in a composite component. See also When to use <ui:include>, tag files, composite components and/or custom components?

查看更多
登录 后发表回答