【问题标题】:Rendering updated components from backing bean after Save保存后从支持 bean 渲染更新的组件
【发布时间】:2013-04-09 03:17:46
【问题描述】:

我一直致力于创建一个动态表,该表捕获所有已更新的单元格(以便更快地保存),然后在保存后刷新/重新呈现这些单元格。

到目前为止,我已经创建了表,所有更新的项目都通过 ajax 侦听器很好地捕获,但现在卡在保存后无法刷新/重新渲染这些更新的组件。

页面中的代码sn-p:

<h:form id="formMain" prependId="false">
  <div id="contentWrapper">
    <p:messages id="messages" severity="warn, error" autoUpdate="true" closable="true" />
    <div style="float:right; position:relative; top: -3px;">
      <h:commandButton id="btnSaveUpdates" styleClass="save_updates_button">
        <f:ajax execute="@this" listener="#{remediationDetail.processUpdates}"/>
      </h:commandButton>
     </div>
   <h:panelGroup id="detailEdit" styleClass="clear_left" layout="block">
     <h:dataTable id="tblDetails" styleClass="slate_table remediation" value="#{remediationDetail.details}" var="dataItem">
                    <c:forEach items="#{remediationDetail.detailHeaders}" var="key" varStatus="looper">
                    <h:column>
                        <f:facet name="header">#{key.fieldDefinition.fieldConfiguration.customLabel}</f:facet>
                      <c:if test="#{key.fieldDefinition.dataType.name eq 'Number'}">
                        <h:panelGroup id="detailNumberPanel#{looper.index}">
                            <h:inputText id="txtDetailNumber#{looper.index}" rendered="#{remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}" styleClass="remediation_textbox error_marker" title="#{remediationDetail.errorMessages(dataItem.id, key.fieldDefinition.id)}">
                                            <f:convertNumber maxFractionDigits="0" maxIntegerDigits="19"/>
                                            <f:ajax event="change" execute="@this" render="@none" listener="#{remediationDetail.markChangedEntity}"/>
                                            <f:attribute name="entity" value="#{dataItem.entityList[looper.index]}"/>
                                        </h:inputText>
                                        <h:outputText id="txtDetailNumberOut#{looper.index}" rendered="#{not remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}"></h:outputText>
                                    </h:panelGroup>
                              </c:if>
                      <c:if test="#{key.fieldDefinition.dataType.name eq 'Decimal'}">
                        <h:panelGroup id="detailDecimalPanel#{looper.index}">
                            <h:inputText id="txtDetailDecimal#{looper.index}" rendered="#{remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" converterMessage="Value provided is not a valid Decimal" styleClass="remediation_textbox error_marker" title="#{remediationDetail.errorMessages(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}">
                                            <f:convertNumber maxFractionDigits="2" maxIntegerDigits="19"/>
                                            <f:ajax event="change" execute="@this" render="@none" listener="#{remediationDetail.markChangedEntity}"/>
                                            <f:attribute name="entity" value="#{dataItem.entityList[looper.index]}"/>
                                        </h:inputText>
                                        <h:outputText id="txtDetailDecimalOut#{looper.index}" rendered="#{not remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}">
                                            <f:convertNumber maxFractionDigits="2" maxIntegerDigits="19"/>
                                        </h:outputText>
                                    </h:panelGroup>
                            </c:if>
                      <c:if test="#{key.fieldDefinition.dataType.name eq 'Date'}">
                        <h:panelGroup id="detailDatePanel#{looper.index}">
                                        <h:inputText id="txtDetailDate#{looper.index}" rendered="#{remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" styleClass="remediation_textbox error_marker dates" title="#{remediationDetail.errorMessages(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}">
                                            <f:convertDateTime locale="en_US" pattern="MM/dd/yyyy" />
                                            <f:ajax event="change" execute="@this" render="@none" listener="#{remediationDetail.markChangedEntity}"/>
                                            <f:attribute name="entity" value="#{dataItem.entityList[looper.index]}"/>
                                        </h:inputText>
                                        <h:outputText id="txtDetailDateOut#{looper.index}" rendered="#{not remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}">
                                            <f:convertDateTime locale="en_US" pattern="MM/dd/yyyy" />
                                        </h:outputText>
                                    </h:panelGroup>
                      </c:if>
                      <c:if test="#{key.fieldDefinition.dataType.name eq 'Boolean'}">
                        <h:panelGroup id="detailBooleanPanel#{looper.index}">
                            <h:selectBooleanCheckbox id="cbDetailBooleanInput#{looper.index}" rendered="#{remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" title="#{remediationDetail.errorMessages(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}">
                                <f:ajax event="change" execute="@this" render="@none" listener="#{remediationDetail.markChangedEntity}"/>
                                            <f:attribute name="entity" value="#{dataItem.entityList[looper.index]}"/>
                                        </h:selectBooleanCheckbox>
                            <h:outputText id="txtDetailBooleanOutput#{looper.index}" rendered="#{not remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}"></h:outputText>
                        </h:panelGroup>
                            </c:if>
                      <c:if test="#{key.fieldDefinition.dataType.name eq 'String'}">
                        <h:panelGroup id="detailStringPanel#{looper.index}">
                                <h:inputText id="txtDetailString#{looper.index}" rendered="#{key.fieldDefinition.inputType eq 'TEXTBOX' and remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}" styleClass="remediation_textbox error_marker" title="#{remediationDetail.errorMessages(dataItem.id, key.fieldDefinition.id)}">
                                            <f:ajax event="change" execute="@this" render="@none" listener="#{remediationDetail.markChangedEntity}"/>
                                            <f:attribute name="entity" value="#{dataItem.entityList[looper.index]}"/>
                                        </h:inputText>
                                        <h:selectOneMenu id="ddDetailString#{looper.index}" styleClass="remediation_select error_marker" rendered="#{key.fieldDefinition.inputType eq 'DROPDOWN' and remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}" title="#{remediationDetail.errorMessages(dataItem.id, key.fieldDefinition.id)}">
                                             <f:selectItems value="#{dataItem.entityList[looper.index].fieldDefinition.listItemSet.selectItemsList}"></f:selectItems>
                                             <f:ajax event="change" execute="@this" render="@none" listener="#{remediationDetail.markChangedEntity}"/>
                                             <f:attribute name="entity" value="#{dataItem.entityList[looper.index]}"/>
                                        </h:selectOneMenu>
                                        <h:outputText id="txtDetailStringOut#{looper.index}" rendered="#{not remediationDetail.containsErrors(dataItem.id, key.fieldDefinition.id)}" value="#{dataItem.entityList[looper.index].val}"></h:outputText>
                                    </h:panelGroup>
                      </c:if>
                    </h:column> 
                    </c:forEach>
                </h:dataTable>
            </h:panelGroup>
        </div>
    </h:form>

来自支持 bean 的代码

@ManagedBean
@SessionScoped
public class RemediationDetail implements Serializable {
public void markChangedEntity(AjaxBehaviorEvent ajaxEvent){
    Entity entity = (Entity) Utility.getAjaxActionAttribute(ajaxEvent, "entity");
    //Capture the Client Ids that were updated
    getComponentsIdsToRefresh().add(ajaxEvent.getComponent().getParent().getClientId());
    //Capture what Entities were changed    
    getChangedEntities().add(entity);
}

 //This is where the save happens and hoping for updating of components !!
 public void processUpdates(AjaxBehaviorEvent event){
    entityDomain.processEntities(changedEntities);

    FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().addAll(getComponentsIdsToRefresh());
}

}

保存发生后,我将要更新的客户端 ID 添加到 PartialViewContext().getRenderIds() 我没有看到任何更新。我也尝试过 OmniFaces Ajax.Update(clientId) 也没有成功。

我已经更新了代码 sn-ps,因为它当前与正在构建的完整表保持一致。

我的问题是:

  1. 我正在做的事情可能吗?
  2. 我是否正确处理了组件的渲染?
  3. 我错过了什么?

我的环境: 莫哈拉 2.1.7 雄猫 7.022

问候,

迈克

【问题讨论】:

  • 您确定要更新的组件标识有效吗?你的 Javascript 控制台说什么?
  • @kolossus 是的!我确实查看了传递给支持 bean 的内容以及页面上可用的内容。更进一步,我通过将“formMain:”添加到 ID 甚至“:formMain:”来更改值,因为它会在 f:ajax 标记的渲染部分中使用,到目前为止,什么都没有用。
  • @MikeR 您的托管 bean 的范围是什么?
  • @partlov bean 是 SessionScoped
  • 无法重现您的问题。请提供 SSCCE 并提及确切的 JSF impl/version 和容器 impl/version。还请提供 ajax 请求和响应的原始副本。

标签: ajax dynamic jsf-2 renderpartial


【解决方案1】:

这段代码在 Mojarra 2.1.21 上运行良好。 Mojarra 2.1.7 是从 2012 年 3 月开始的,因此目前已经有 1 年多一点的历史了。我强烈建议升级它。

我无法准确指出 2.1.7 和 2.1.21 之间的哪个版本和/或哪个 Mojarra issue 解决了 2.1.7 的具体问题,因为我不认识这个问题,但我可以说很多最近在视图状态管理中得到了改进。更何况,从2.1.18开始,eternal chicken-egg problem with taglibs+viewscope已经被修复了,还不如关联起来。

【讨论】:

    【解决方案2】:

    我注意到您的 markChangedEntity 方法中有一些内容。你有以下代码:

    getComponentsIdsToRefresh().add("formMain:" + 
        ajaxEvent.getComponent().getParent().getClientId());
    

    调用getClientId() 已经返回完整的ID,包括表单的ID。添加formMain: 将导致类似formMain:formMain:XXX 的内容,在您看来这不是合法ID。

    【讨论】:

    • 这很奇怪。编辑前的原始问题代码没有那个错误。我不确定这是否只是 OP 在制定/编辑问题时的粗心大意。
    • @Michi “:formMain:” 在我的原始帖子中不存在,是我在尝试解决此问题时添加的。现在这是关键点。我改变了捕获 ID 的方式,它现在可以工作,但只有当我将它与 BalusC 将 JSF 版本升级到 2.1.21 的建议结合起来时它才有效。这个应该怎么处理?
    • @Michi 另外,作为快速评论。检查 getClientId() 我没有在返回的值中看到表单。它只返回到 table 标记。
    • 您绝对应该按照 BalusC 的建议(甚至更好的 Apache MyFaces)使用当前版本的 Mojarra。这可能是您使用的 Mojarra 版本中的一个错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    • 2011-01-20
    • 2013-04-13
    • 1970-01-01
    • 2022-06-30
    • 2018-07-05
    相关资源
    最近更新 更多