代码之家  ›  专栏  ›  技术社区  ›  Tuukka Mustonen

jsf2.0:使用请求范围的bean呈现带有初始数据的表单字段(以更新特定于当前组件的服务器数据)

  •  0
  • Tuukka Mustonen  · 技术社区  · 14 年前

    很正常的情况:

    我们有一个“portlet”复合组件,它有两种状态:展开和折叠。Portlet开始时是展开的,但用户可以通过单击它们来折叠它们。这个状态应该保存到会话中,这样一旦用户刷新页面或导航到新的页面,portlet就会记住它们是否被展开/折叠。

    :如何将这种状态保存到可以在页面上多次插入的组件中?

    通过使用会话范围的bean,可以很容易地实现一个portlet的状态保存。通过创建固定数量的会话作用域bean或在一个bean中声明不同的属性,也可以支持固定数量的portlet。然而,我甚至不想提及为什么这些方法是不好的。

    我最初的想法是在单个会话bean下创建一个映射(或一些对象结构),以保存所有portlet的状态。但是,我不能直接从JSF引用这些数据(这样JSF也会更新它们)。我考虑编写一个特定的getter/setter来获取/更新映射中的正确值,但这是不可能的,因为在getter和setter的执行过程中没有标识数据。

    不过,很明显我需要将状态保存到会话bean中。我可以通过发布一个带有 f:ajax listener 以及提交的数据。为了支持组件的多个实例,我可以使用请求范围的bean(多个实例)来处理每个扩展/折叠。但是,为了实际发布标识portlet及其状态的数据,我需要在呈现时首先将其插入表单字段。

    • h:inputHidden h:inputText 除了value属性(指向 #{portletBean.portletState} ).

    我又一次觉得我错过了什么。。。指针?

    UIComponent 而不是复合组件,但我希望将其作为复合组件,因为它包含许多原始HTML元素。

    更新:

    3 回复  |  直到 8 年前
        1
  •  0
  •   Tuukka Mustonen    14 年前

    我有一些可能的黑客。我会把它们贴在这里,但我不认为这是真正的方式:

    使用javascript设置表单字段 渲染后直接使用正确的数据:

    window.addEvent('domready', function() {
        var portletState = '#{portletBean.getPortletState(cc.attrs.clientId)}';
        // find the field and set the data...
    });
    

    使用组件的属性映射保存数据:

    <cc:interface>
        <cc:attribute name="portletState" default="#{portletBean.getPortletState(cc.attrs.clientId)}" />
    </cc:interface>
    

    从以下代码访问:

    public void stateChangedCallback(String clientId) {
        UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(clientId);
        String state = (String) component.getAttributes().get("portletState");
    }
    

    也感觉不对。我也不确定它是否有效(你能在默认属性中使用EL吗)。

    使用组件的属性映射 要通过在调用组件时提供数据来保存数据,请执行以下操作:

    <portlet:portlet id="specificPortlet">
        <f:attribute name="portletState" value="#{portletBean.getPortletState(component.clientId)}" />
    </portlet:portlet>
    

    同样,非常笨拙,重复您的代码。

        2
  •  0
  •   Matthew Farwell    14 年前

    您可以使用taglibs执行此操作,您可以将参数传递到标记中:

    将以下内容添加到taglib:

    <tag>
        <tag-name>date</tag-name>
        <source>components/date.xhtml</source>
    </tag>
    

    下面是组件的内容/日期.xhtml

    <ui:composition name="date_template">
        <h:panelGrid id="#{id}Panel" columns="1" border="0" cellpadding="0" cellspacing="0">
            <rich:calendar immediate="true" id="#{id}" popup="true" datePattern="dd.MM.yyyy"
                            enableManualInput="true" showApplyButton="true" cellWidth="12px" cellHeight="11px" style="width:100px"
                            value="#{dateForm.date}" required="#{required}" readonly="#{readonly}" validator="#{dateForm.validateDate}">
                <a4j:support event="onchanged" reRender="#{id}Panel,#{reRenderDate}"/>
                <ui:insert />
            </rich:calendar>
    
            <rich:message for="#{id}" errorClass="error" />
        </h:panelGrid>
    </ui:composition>
    

    <adse:date id="dateTransfert" required="true"
               dateForm="#{dossierBean.dateTransfert}"
               readonly="false" reRenderDate="montantAncien,montantNouveau,montantEmolument">
         <a4j:support event="oninputblur" reRender="dateTransfertPanel,montantAncien,montantNouveau,montantEmolument"/>
    </adse:date>
    

    在本例中,传递了dateForm,这是一个对象,在taglib中我们使用该对象的属性(dateForm.date日期).

        3
  •  0
  •   Community CDub    8 年前

    我用了一个 previously solved hack to call a bean method from JS

    创造了一个空的,看不见的形式 h:commandButton f:ajax 在里面呼叫 listener .

    为启动展开/折叠事件创建了一个单独的按钮。从该按钮启动javascript方法,该方法为展开/折叠设置动画,同时单击窗体内的隐藏按钮。所有需要的数据都使用 听众

    然而,它还远远不够完美,它没有回答如何用默认值启动请求范围内的bean以将它们用作存储/传输形式。