【问题标题】:Multiple instances of a composite component in a view?视图中复合组件的多个实例?
【发布时间】:2013-02-27 15:15:37
【问题描述】:

我读了很多类似的问题,但我不知道如何解决我的问题:

我编写了一个复合组件,该组件由视图范围的自包含托管 bean 提供支持。
该组件由一个自动完成文本框和一个打开对话框的按钮组成。用户可以通过名称(自动完成)或在树中选择一个节点(对话框)来选择一个项目。
支持 bean 实现了所有需要的东西(数据访问、树逻辑等),并且应该公开选定的项目(作为 POJO)。

现在我有两个问题:

  1. 由于树管理的复杂性,selectedObj 属性由在 bean 中执行某些操作的 getter 和 setter 访问:它们不只是访问类字段。现在我将整个 bean 作为属性传递。我怎样才能让 bean 的 selectedObj 成为我的复合组件的“值”属性?

  2. 如何在同一个视图中使用我的组件的多个实例?

这是一个组件示例:

<cc:interface>
    <cc:attribute name="bean" type="com.yankee.OUTreeBean" required="true"/>
    <cc:attribute name="listener" method-signature="void listener()"/>
</cc:interface>
<cc:implementation>
    <p:dialog id="#{cc.id}_dialog" widgetVar="_dlg" header="Select OU" modal="true" dynamic="true" >
        <p:toolbar>
            <!-- some buttons to refresh, expand, collapse etc. -->
        </p:toolbar>
        <p:tree id="#{cc.id}_tree" value="#{cc.attrs.bean.root}" var="node"
                selectionMode="single"
                selection="#{cc.attrs.bean.selectedNode}">
            <p:ajax event="select" update="@form" listener="#{cc.attrs.listener}" oncomplete="if (!args.validationFailed) _dlg.hide()" />
            <p:treeNode>  
                <h:outputText value="#{node.OU_NAME}" />  
            </p:treeNode>  
        </p:tree>
    </p:dialog>

    <p:autoComplete id="#{cc.id}_inner" value="#{cc.attrs.bean.selectedObj}" completeMethod="#{cc.attrs.bean.completeObj}"  
                    var="obj" itemLabel="#{obj.OU_NAME}" itemValue="#{obj}" 
                    forceSelection="true" 
                    converter="ouConverter"
                    multiple="false" 
                    minQueryLength="2">
        <p:ajax event="itemSelect" listener="#{cc.attrs.listener}" update="@form"/>
    </p:autoComplete>
    <div style="float: right">
        <p:commandButton id="bSearch" icon="ui-icon-search" onclick="_dlg.show()"/>
    </div>
</cc:implementation>

COMPONENT 的支持 bean:

@ManagedBean
@ViewScoped
public class OUTreeBean implements Serializable {
    private static final long serialVersionUID = 1L;

    private List<OU> data;  // Data as plain list
    protected TreeNode root;  // root node of data as a tree
    protected TreeNode selectedNode;

    @PostConstruct
    private void init() throws SQLException {
        refreshData();
    }

    public OU getSelectedObj() {
        if (selectedNode == null) {
            return null;
        }
        return ((OU) selectedNode.getData());

    }
    public void setSelectedObj(OU ou) {
        // Find the right tree node and do whatever needed
    }
    public TreeNode selectedNode getSelectedNode() {
        // Blah blah
    }
    public void setSelectedNode(TreeNode selectedNode) {
        // Blah blah
    }
    public List<OU> completeObj(String namePattern) {
        // Autocomplete handler
    }
    public void refreshData() {
        // Blah blah
    }
    // etc...

}

使用页面摘录:

<ism:selectOUTree id="cbSelectOu" bean="#{myBean.ouFilterBean}" listener="#{myBean.onOUChange}"/>

PAGE 的支持 bean:

@ManagedBean
@ViewScoped
public class MyBean implements Serializable {

    private static final long serialVersionUID = 1L;
    @ManagedProperty("#{oUTreeBean}")
    private OUTreeBean ouFilterBean;

    public void onOUChange() throws SQLException {
        // Blah blah
    }
}

【问题讨论】:

  • 它应该与 #{cc.attrs.value} 一起使用,如果你有正确的 getter 和 setter,value="#{myBean.ouFilterBean.selectedObj}"
  • @Christophe Roussy 好的,谢谢,但目的是从页面的 bean 中“隐藏”组件的支持 bean。 MyBean 应该不知道 OUTreeBean 的存在,因此该组件应该绑定到 MyBean 类型为 OU 的属性
  • 在 myBean 中提供一些 getter 和 setter,这样就可以直接访问对象(通过实现接口来强制执行...)

标签: jsf-2 composite-component


【解决方案1】:

几天前我遇到了同样的问题。就像你一样,我使用 ManagedBean 作为应该完成这项工作的对象。一段时间后,我发现我应该只创建FacesComponent。我是 JSF 的新手,所以找到解决方案并不容易,但它解决了我所有的问题。它是这样工作的:

view.xhtml

<h:body>
    <cc:interface componentType="playerComponent">
        <cc:attribute name="playerId" required="true"/>
    </cc:interface>
    <cc:implementation>
        <c:set var="inplaceId" value="inplace-#{cc.attrs.playerId}" />
        <c:set var="outputId" value="output-#{cc.attrs.playerId}" />
        <h:form id="form-#{cc.attrs.playerId}">
            <p:inplace editor="false" widgetVar="#{inplaceId}">
                <h:inputText value="#{cc.player.name}" id="outputId"/>
                <p:commandButton onclick="#{inplaceId}.save()" action="#{cc.save}" update="#{outputId}" value="save" />
                <p:commandButton onclick="#{inplaceId}.cancel()" update="#{outputId}" value="cancel"  />
            </p:inplace>
        </h:form>
    </cc:implementation>
</h:body>

PlayerComponent.java

@FacesComponent("playerComponent")
public class PlayerComponent extends UINamingContainer {

    private Player player;

    private void init() {
        Object idObj = getAttributes().get("playerId");
        if (idObj != null) {
            // create player object
        }
    }

    public void save() {
        // save player object
    }

    public Player getPlayer() {
        if (player == null) {
            init();
        }
        return player
    }
}

Player.java(实体)

public class Player {
    private name;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

正如我所写的,我是 JSF 的新手,可能应该以不同的方式创建播放器对象(在构造函数中使用 @PostConstruct?)但是这个工作。

【讨论】:

  • 谢谢你。我还尝试将我的@ManagedBean 转换为@FacesComponent,但我不知道如何将组件值绑定到参数,例如您如何在页面中“使用”&lt;h:inputText value="#{cc.player.name}" 以及如何将其绑定到页面的支持 bean?
  • @yankee, &lt;h:inputText value="#{cc.player.name}" 通过 getter public Player getPlayer() 方法绑定到对象参数。只有当player 对象为空时,播放器对象才会在init 方法中初始化。如果你想在FacesComponent 中获取你的属性,你可以使用getAttributes().get("attributeName") 方法。
  • 我刚刚发现自定义组件具有请求范围,甚至使用状态助手(参见 BalusC 对 this question 的回答)来模仿 @ViewScope 对我来说太复杂了,因为会有一些要重新创建的对象。相反,parent/child bean approach 似乎适用于问题 2)。我仍然无法理解您对 1) 的处理方式
  • 方法1)是什么?
  • 我的问题 1) ;-) &lt;p:tree selection="#{cc.attrs.bean.selectedNode}"/&gt; 是一个 TreeNode,里面有一个 OU&lt;p:autoComplete value="#{cc.attrs.bean.selectedObj}"/&gt; 已经是一个 OU。所以我需要特定的 Getter/Setter 来访问选定的 OU(参见OUTreeBean 代码)。它们不能是使用 bean MyBean 的一部分:它们必须在 OUTreeBean 中。但我不想像我在这里所做的那样将整个 OUTreeBean 暴露给用户(参见&lt;cc:attribute name="bean" type="com.yankee.OUTreeBean" required="true"/&gt;)。相反,我必须找到一种方法将选定的OU 公开(绑定)为属性
猜你喜欢
  • 1970-01-01
  • 2020-07-02
  • 1970-01-01
  • 2018-03-24
  • 2011-11-15
  • 2014-08-15
  • 1970-01-01
  • 2017-12-09
  • 1970-01-01
相关资源
最近更新 更多