PrimeFaces 8 - Lazy p:dataScroller - 拖放问题

发布时间:2021-03-06 17:16

我们使用带有 p:dataScrollerLazyDataModel 来显示可以从延迟加载的搜索结果中拖出并放入购物车的产品。

当加载了多个结果块时,我们只能从最近的数据块中拖放项目。如果我尝试将第一个区块中的物品放入我的购物车,它将错误地从最近加载的区块中放入相应的物品。

示例:在 DataScroller 执行 3 次延迟加载(显示 3 个块)后,如果我尝试从结果的第一个或第二个块中删除第 5 个项目,则从第 3 个块中删除第 5 个项目的结果将由 DragDropEvent.getData() 方法返回。

我们的 Facelets 模板看起来像这样。 droppable 元素是粘性标题,它是一个 id = headerPanel 的 div。

  <h:body>
    <h:form id="form1">
      <p:growl id="msgs" showDetail="true" life="2000">
        <p:autoUpdate />
      </p:growl> 
      <h:panelGroup id="headerPanel" layout="block" styleClass="header">
        <ui:include src="/WEB-INF/includes/layout/Header.xhtml" />
      </h:panelGroup>
      <p:droppable for="headerPanel" 
                   scope="shoppingCartAdd" 
                   datasource="productScroller" 
                   hoverStyleClass="dragActive"
                   tolerance="touch">
        <p:ajax listener="#{shoppingCart.addProductToShoppingCart}" 
                update="shoppingCartButton shoppingCartSidebar" />
      </p:droppable>
      <ui:include src="/WEB-INF/includes/layout/ShoppingCartBar.xhtml" />
      <h:panelGroup id="contentPanel" layout="block" styleClass="content">
        <ui:insert name="contentPanel">Content</ui:insert>
      </h:panelGroup>
    </h:form>
  </h:body>

p:draggable 元素位于定义我们 Facelets 模板中的 contentPanel 的 ui 组合中的 p:dataScroller 内:

<ui:composition template="/WEB-INF/templates/Layout.xhtml">

  <ui:param name="title" value="Product Search" />

  <ui:define name="contentPanel">
      <p:commandButton id="submitButton" 
                       action="#{productSearchBean.searchAction}" 
                       ajax="false" 
                       value="Find All Products" />
      <h:panelGrid id="resultsGrid" styleClass="resultsGrid">
        <p:dataScroller id="productScroller" 
                        buffer="5"
                        chunkSize="10" 
                        lazy="true"
                        rendered="#{productSearchBean.productList.rowCount > 0}"
                        rowIndexVar="resultIndex"
                        styleClass="scroller"
                        value="#{productSearchBean.productList}" 
                        var="rowProduct">
          <p:panel id="searchResultsPanel" 
                   header="#{resultIndex + 1} - Product ##{rowProduct.productId}" 
                   closable="true" 
                   toggleable="true" 
                   styleClass="searchResultsPanel">
            <h:panelGrid id="productDataGrid" columns="2" columnClasses="thumbnailPanel, textPanel">
              <h:panelGroup id="imageDiv" layout="block" styleClass="thumbnailContainer">
                <span class="alignmentHelper" />
                <p:graphicImage id="thumbnailImage" styleClass="thumbnailImage" value="#{rowProduct.thumbnailUrl}" />
                <p:draggable for="thumbnailImage" helper="clone" revert="true" scope="shoppingCartAdd" />
              </h:panelGroup>
              <h:panelGrid id="textDataGrid" columns="2" columnClasses="padRight, padLeft">
                <h:outputText value="id:" /> #{rowProduct.productId}<br/>
                <h:outputText value="name:" /> #{rowProduct.productName}<br/>
              </h:panelGrid>
            </h:panelGrid>
          </p:panel>
        </p:dataScroller>
      </h:panelGrid>
  </ui:define>
</ui:composition>

这是在放置事件上调用的侦听器方法。如上所述,如果发生多次延迟加载并且用户试图从除最新数据块之外的任何内容拖放项目,则 DragDropEvent.getData() 方法返回错误的数据项:

  public void addProductToShoppingCart(DragDropEvent shoppingCartDropEvent) {
    Long draggedId = productIdFromDragDrop(shoppingCartDropEvent);
    if (addProductToDefaultShoppingCart(userId, draggedId)) {
      fetchShoppingCartProducts();
      addSuccessMessage(draggedId);
    }
    else {
      addErrorMessage(draggedId);
    }
  }

  private Long productIdFromDragDrop(DragDropEvent productDroppedEvent) {
    Long droppedProductId = null;
    Object dropObj = productDroppedEvent.getData();
    if (dropObj != null && dropObj instanceof ProductView) {
      ProductView view = (ProductView) dropObj;
      droppedProductId = view.getProductId();
    }
    return droppedProductId;
  }

感谢阅读:)

回答1