视图中复合组件的多个实例?

时间:2013-02-27 15:15:38

标签: jsf-2 composite-component

我读了许多类似的问题,但我无法弄清楚如何解决我的问题:

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

现在我有两个问题:

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

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

  3. 以下是该组件的示例:

    <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
        }
    }
    

1 个答案:

答案 0 :(得分: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?)但是这样做。