Primefaces data for data table is getting confused

2019-09-16 03:50发布

问题:

Sorry for the title but I have to explain what I want to do and what isn't working. My web ui with JSF 2.2.10 and primefaces 5.2.6 shows a search mask and search results upon a model. Each search instance is shown as a tab in a tabView. When a tab is clicked, its corresponding search instance is shown under the tabView in a dataTable. A search instance is created upon a search template, so different search instances can have different input fields and different result fields (which are the columns in the data table). The user is able to execute the search for an existing search instance again with or without changed search fields. Here is my problem...he ui work until the user has executed a search instance 2nd time. Now when the tab in the tabView is changed an exception is thrown and the javascript console shows 'Request return with error:parsererror primefaces.js.jsf?ln=primefaces$v=5.2.6:1' Now the data of for instance search instance 1 is mixed up with search instance 2. A result field (data table column) from search instance 1 is tried to get from search instance 2, but this can fail. This only occurs if a search instance is executed the 2nd time. Without 2nd execution I can change between the tabs without problem. My data structure is ok I think. A class SearchInstance is "behind" a tab and contains a list of SearchResult. This SearchResult is a Map with the result fields.

This is the xhtml of the tabView. The tabView is only used as trigger here. A tab does not really contain the dataTable with the components, it updates only the form and the content is included under the tabView:

<h:form id="searchInstancesFormId">
    <p:tabView id="searchTabViewId" value="#{searchBL.searchInstances}" var="curSearch" activeIndex="#{searchBL.activeTabIndex}">
        <p:ajax event="tabChange" oncomplete="resizeResultViews();" listener="#{searchBL.setSelectedSearch(curSearch)}"
            update="@form" immediate="true" process="@this" />
        <p:ajax event="tabClose" listener="#{searchBL.removeSearchInstance(curSearch)}" update="@this"
            oncomplete="resizeResultViews();" immediate="true" process="@this" />
        <p:tab closable="#{curSearch.isCloseable()}">
        </p:tab>
    </p:tabView>

    <h:panelGrid id="mainSearchAreaGridId">
        <ui:include
            src="#{not searchBL.selectedSearch.closeable ? '/sections/search/firstSearchTab.xhtml' : '/sections/search/searchInstanceTab.xhtml'}">
            <ui:param name="curSearchInst" value="#{searchBL.selectedSearch}" />
        </ui:include>
    </h:panelGrid>
</h:form>

The 1st tab is the search template tab from the 2nd tab on there are search instances.

Here is the dataTable xhtml. The problem occurs when curValue is retrieved. Here in 'hitlistBL' bean the result field map is queried with the current property name. Here the name from the search instance selected before and it is tried to get the value from the new selected search instance:

<p:dataTable id="searchResultTableId" scrollable="true" value="#{curSearch.getSearchResults()}" scrollHeight="300" var="curSearchResult"
    sortMode="multiple" rowKey="#{curSearchResult.hashCode()}" draggableColumns="true" resizableColumns="true" styleClass="hitlistDataTable"
    paginator="true" rows="#{curSearch.hitlistRowsPerPage}" rowIndexVar="rowIndex" filteredValue="#{curSearch.filteredValues}" 
    selection="#{curSearch.selectedSearchResults}" widgetVar="hitlistTableVar">

    <p:ajax event="rowSelect" update="@(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
    <p:ajax event="rowUnselect" update="@(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
    <p:ajax event="toggleSelect" update="@(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
    <p:ajax event="rowSelectCheckbox"
        update="@(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
    <p:ajax event="rowUnselectCheckbox"
        update="@(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
    <p:ajax event="contextMenu" update="@(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId"
        oncomplete="PF('searchResultTableContextMenuVar').show(currentEvent);" />

    <!-- double click listener -->
    <p:ajax event="rowDblselect"
        listener="#{editPropertyBL.initForEdit(curSearch.selectedSearchResults.get(0), curSearch.getDataViewDefinition())}"
        oncomplete="PF('editPropertyDialogVar').show();" update=":editPropertyFormId @(.resultlistActionGrid)" />

    <p:column style="width: 16px;">
        <p:rowToggler />
    </p:column>
    <p:column selectionMode="multiple" style="width: 16px; text-align:center; padding-right: 12px;" />

    <p:columns value="#{curSearch.determinePrimaryPropertyNames()}" var="curPrimaryPropName"
        sortBy="#{curSearchResult[curPrimaryPropName].getValue()}" filterBy="#{curSearchResult[curPrimaryPropName].getValue()}"
        filterMatchMode="contains">

        <f:facet name="header">
            <h:outputText value="#{displayNameResolver.resolveDisplayNameOfHitlistProperty(curPrimaryPropName, curSearch)}" />
        </f:facet>

        <ui:param name="curValue" value="#{hitlistBL.generatePropertyValue(curSearchResult, curPrimaryPropName)}" />
        <ui:param name="isDocumentTitle" value="#{hitlistBL.isDocumentTitle(curPrimaryPropName)}" />
        <ui:param name="isChoice" value="#{hitlistBL.isChoice(curPrimaryPropName, curSearch)}" />

        <!-- doc title -->
        <h:panelGroup rendered="#{curSearchResult.isChanged() and (isDocumentTitle)}" style="padding-right: 4px;">
            <i class="fa fa-refresh" />
        </h:panelGroup>
        <!-- <p:commandLink action="#{contentBL.showContentExtern(curSearch.getViewId(), curSearchResult)}" value="#{curValue}" ajax="false"
            rendered="#{(curSearchResult.isOfDataType('STRING', curPrimaryPropName)) and (isDocumentTitle) and (not isChoice)}" target="_blank" /> -->

        <!-- document title -->
        <h:outputText value="#{curValue}" title="#{curSearchResult.getRepresentationsAsString()}"
            rendered="#{(curSearchResult.isOfDataType('STRING', curPrimaryPropName)) and (isDocumentTitle) and (not isChoice)}" />

        <!-- data type STRING -->
        <h:outputText value="#{curValue}"
            rendered="#{curSearchResult.isOfDataType('STRING', curPrimaryPropName) and (not isDocumentTitle) and (not isChoice)}" />

        <!-- data type UUID -->
        <h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('UUID', curPrimaryPropName) and (not isChoice)}" />

        <!-- data type INTEGER32 -->
        <h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('INTEGER32', curPrimaryPropName) and (not isChoice)}">
            <f:convertNumber integerOnly="true" groupingUsed="false" />
        </h:outputText>

        <!-- data type DOUBLE -->
        <h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('DOUBLE', curPrimaryPropName) and (not isChoice)}">
            <f:convertNumber groupingUsed="false" />
        </h:outputText>

        <!-- data type DATETIME -->
        <h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('DATETIME', curPrimaryPropName) and (not isChoice)}">
            <f:convertDateTime type="both" dateStyle="short" timeStyle="short" timeZone="#{settingsBL.getTimeZoneIdSet()}"
                pattern="#{settingsBL.dateTimePattern}" />
        </h:outputText>

        <!-- CHOICE -->
        <h:outputText value="#{hitlistBL.determineChoiceUiValue(curSearch.getViewId(), curSearchResult, curPrimaryPropName)}"
            rendered="#{(not isDocumentTitle) and (isChoice)}" />

    </p:columns>
</p:dataTable>

A search instance if executed with the following. A new search is done and the search instance member search result is exchanged with the new results:

<p:commandButton id="doSearchButtonFullMaskId" value="#{msgs['label.button.searchTemplate.search']}" icon="searchButtonIcon"
                styleClass="searchButton" action="#{searchMaskBL.doSearch(curSearchInst)}" update="@form" process="@form"
                oncomplete="resizeResultViews(); PF('hitlistTableVar').clearFilters();" style="margin-top: 10px;" />

Sorry this is a lot of text and it is quite difficult to explain. I don't know if this is my flaw or there is a bug somewhere. Maybe this javascript parsererror could give a hint, but I do not know how to get into/debug it.

Update: looks like a not wellformed xml of the ajax response?:

XML-Verarbeitungsfehler: nicht wohlgeformt Adresse: moz-nullprincipal:  {96f3db57-4075-4d80-a250-03491a2ce33f} Zeile Nr. 90, Spalte 132: ...rrorpages/500.xhtml?dswid=-9189"></redirect>]]>]]></update></partial-response......-------------------------------------------------^

It points to the closing brackets of ></redirect>]]>]]><