JSF rendert XHTML zu früh

DaBe1812

Bekanntes Mitglied
Hi,
ich habe folgende Seite:
HTML:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
    template="../layout.xhtml">

    <ui:define name="header">
        ProIPS - Datenpflege
    </ui:define>

    <ui:define name="main">

        <f:event type="preRenderView" listener="#{proIpsSearchHandler.onLoad}" />

        <h:form id="datenpflegeForm">
            <p:growl id="msgs" showDetail="true" skipDetailIfEqualsSummary="true" />

            <div class="card">
                <p:tabView dynamic="true" id="tabViewProIps" widgetVar="tabViewProIps"
                        value="#{proIpsSearchHandler.openTabList}" style="padding:0" var="openTab"
                        cache="false" scrollable="true" rendered="#{openTab.inited}">
                    <p:ajax event="tabChange" listener="#{proIpsSearchHandler.onTabChange}" update=":datenpflegeForm:msgs" />
                    <p:ajax event="tabClose" listener="#{proIpsSearchHandler.onTabClose}" update=":datenpflegeForm:msgs" />
                    <p:tab title="#{openTab.title}" closable="#{openTab.closable}" >
                        <ui:include src="./dataexplorer/#{openTab.subpage}.xhtml" />
                    </p:tab>
                </p:tabView>
            </div>
        </h:form>
    </ui:define>
</ui:composition>

Wenn ich die laden möchte kommt es zu folgendem Fehler:
Code:
java.io.FileNotFoundException: Facelet /proips/dataexplorer/.xhtml not found at: file:/C:/Projekte/ATCworkspace/AssetToConnector/WebContent/proips/dataexplorer/.xhtml
at org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory._createFacelet(DefaultFaceletFactory.java:376)
at [internal classes]

Aber eigentlich sollte die Eigenschaft openTab.subpage nicht leer sein, weil ich diese initialisieren lassen:
Java:
    public void onLoad() {
        openTabList.add(new OpenTabObj("Suche", "search", null, false));
    }

Beim Debuggen habe ich aber schon gesehen, dass er nie an den Code ran kommt. Scheinbar versucht er erst die Seite zu interpretieren und dann erst lädt er die Bean.

Ich möchte an der Stelle dynamisch Tabs darstellen. Also die Suche soll immer als erster Tab angezeigt werden und dann kann man die Suchergebnisse öffnen und für jedes geöffnete Ergebnis gibt es einen neuen Tab.
Problem ist aber, dass es verschiedene Unterseiten gibt, je nach Typ des Ergebnis.
Mit einer Reihe von vorher gesuchten Ergebnissen aus einer einzigen Entität hat das schon geklappt, nur verzählt sich Primefaces scheinbar dann bei der Tab-Nummer und der Anzahl der Tabs, wenn man ein Tab schließt.

Aber an der Stelle würde ich jetzt einfach gerne Tabs mit dynamischen Namen laden.
 

DaBe1812

Bekanntes Mitglied
Moin,
also deferred war ein guter Input, den hatte ich noch nicht probiert. Leider bleibt das Ergebnis dasselbe.
Die Version mit PostConstruct hatte ich schon hinter mir, auch das wird vor dem Fehler nicht aufgerufen, deswegen hatte ich die Hoffnung, dass wenn ich vor der "falschen" Zeile den Event parke, dann wird vielleicht erst die Bean initialisiert und dann die Seite fertig "geparst".

Also ich bleibe bei meiner Vermutung, der Server versucht scheinbar erst die Syntax der XHTML zu verstehen und will das include auswerten, bevor etwas anderes passiert.
Deswegen würde ich das Include gerne bis zum Laden der Seite "verstecken".
Seite sieht jetzt so aus:
HTML:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
    template="../layout.xhtml">

    <ui:define name="header">
        ProIPS - Datenpflege
    </ui:define>

    <ui:define name="main">

        <h:form id="datenpflegeForm">
            <p:growl id="msgs" showDetail="true" skipDetailIfEqualsSummary="true" />

            <div class="card">
                <p:tabView dynamic="true" id="tabViewProIps" widgetVar="tabViewProIps"
                        value="#{proIpsSearchHandler.openTabList}" style="padding:0" var="openTab"
                        cache="false" scrollable="true" rendered="#{openTab.inited}">
                    <p:ajax event="tabChange" listener="#{proIpsSearchHandler.onTabChange}" update=":datenpflegeForm:msgs" />
                    <p:ajax event="tabClose" listener="#{proIpsSearchHandler.onTabClose}" update=":datenpflegeForm:msgs" />
                    <p:tab title="#{openTab.title}" closable="#{openTab.closable}" deferred="true">
                        <p:outputPanel deferred="true" loaded="#{openTab.inited}" class="mt-2">
                            <ui:include src="./dataexplorer/#{openTab.subpage}.xhtml" />
                        </p:outputPanel>
                    </p:tab>
                </p:tabView>
            </div>
        </h:form>
    </ui:define>
</ui:composition>

Und die Bean mal komplett:
Java:
@Named
@ViewScoped
public class ProIpsSearchHandler implements Serializable {

    private static final long serialVersionUID = -649695753272514273L;

    @Inject    private Instance<SearchableEntityFactoryInterface> searchFactories;
    @Inject private WindowsOrderFactory windowsOrderFactory;
    private SearchableEntityFactoryInterface selectedInterface;

    private List<String> selectableInterfaceNames;
    private String selectedInterfaceName;

    private String searchString;
    
    private List<SearchableEntity> searchResults;
    private List<SearchResultField> columns;
    
    private SearchableEntity selectedDetailEntity;
    private List<OpenTabObj> openTabList = new ArrayList<>();
    
    private boolean inited = false;
    
    @PostConstruct
    public void init() {
        selectableInterfaceNames = new ArrayList<>();
        for(SearchableEntityFactoryInterface entityFactoryInterface : searchFactories) {
            selectableInterfaceNames.add(entityFactoryInterface.getEntityDisplayName());
        }

        openTabList.add(new OpenTabObj("Suche", "search", null, false));
//        searchResults = windowsOrderFactory.searchEntity("23071");
//       
//        boolean jiggle = true;
//       
//        for(SearchableEntity entity : searchResults) {
//            OpenTabObj tabObj = new OpenTabObj(entity.getIdentityField(), entity.getDetailViewName(), entity, jiggle);
//            jiggle = !jiggle;
//            openTabList.add(tabObj);
//        }
        inited = true;
    }

    public void search() {
        if(selectedInterface == null) {
            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Fehler", "Es wurde keine Entität ausgewählt");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            return;
        }
        
        searchResults = selectedInterface.searchEntity(searchString);
        columns = selectedInterface.getResultFields();
    }
    
    public void showDetails(SearchableEntity result) {
        String headLine = result.getIdentityField();
        String detailView = result.getDetailViewName();
        OpenTabObj oto = new OpenTabObj(headLine, detailView, result, true);
        openTabList.add(oto);
        selectedDetailEntity = result;
    }
    
    public void setSelectedInterfaceName(String selectedInterfaceName) {
        for(SearchableEntityFactoryInterface entityFactoryInterface : searchFactories) {
            if(entityFactoryInterface.getEntityDisplayName().equals(selectedInterfaceName)) {
                this.selectedInterface = entityFactoryInterface;
                break;
            }
        }
        this.selectedInterfaceName = selectedInterfaceName;
    }

    public void onTabChange(TabChangeEvent<?> event) {
//        FacesMessage msg = new FacesMessage("Tab Changed", "Active Tab: " + event.getTab().getTitle());
//        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

    public void onTabClose(TabCloseEvent<?> event) {
//        FacesMessage msg = new FacesMessage("Tab Closed", "Closed tab: " + event.getTab().getTitle());
//        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

    public String getSearchString() { return searchString; }
    public void setSearchString(String searchString) { this.searchString = searchString; }
    public List<SearchableEntity> getSearchResults() { return searchResults; }
    public List<SearchResultField> getColumns() { return columns; }
    public SearchableEntity getSelectedDetailEntity() { return selectedDetailEntity; }
    public List<OpenTabObj> getOpenTabList() { return openTabList; }
    public SearchableEntityFactoryInterface getSelectedInterface() { return selectedInterface; }
    public void setSelectedInterface(SearchableEntityFactoryInterface selectedInterface) { this.selectedInterface = selectedInterface; }
    public List<String> getSelectableInterfaceNames() { return selectableInterfaceNames; }
    public String getSelectedInterfaceName() { return selectedInterfaceName; }
    public boolean isInited() { return inited; }
}

Gibt es da eine Möglichkeit?
 

DaBe1812

Bekanntes Mitglied
Nope, hatte ich noch nicht probiert, damit wäre Problem 1 gelöst, führte aber zu einem neuen Problem 2
Also die Grundplatte sieht jetzt so aus:
HTML:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
    xmlns:c="http://java.sun.com/jsp/jstl/core" template="../layout.xhtml">

    <ui:define name="header">
        ProIPS - Datenpflege
    </ui:define>

    <ui:define name="main">

        <h:form id="datenpflegeForm">
            <p:growl id="msgs" showDetail="true" skipDetailIfEqualsSummary="true" />

            <div class="card">
                <p:tabView id="pipsTabView" activeIndex="#{proIpsSearchHandler.activeTabIndex}">
                    <c:forEach items="#{proIpsSearchHandler.openTabList}" var="openTab" varStatus="loop">
                        <p:tab title="#{openTab.title}" closable="#{openTab.closable}">
                            <f:subview id="tab_#{loop.index}">
                                <h:panelGroup id="mainTempPanelGroupId" layout="block">
                                    <ui:include src="./dataexplorer/#{openTab.subpage}.xhtml" />
                                </h:panelGroup>
                            </f:subview>
                        </p:tab>
                    </c:forEach>
                </p:tabView>
            </div>
        </h:form>
    </ui:define>
</ui:composition>

Die Suche als erstes wird Problemlos geladen, sie sucht und Ergebnisse werden angezeigt. Der klick zum öffnen eines Detail-Satzes funktioniert scheinbar auch, aber beim Rendern kommt es scheinbar zu einem Problem.
Also ohne eine weitere Aktion, nur das Öffnen des Detailsatzes, es soll noch kein Tab gewechselt werden oder ähnliches. Wenn ich als Detailansicht folgendes nehme:
HTML:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">

    <f:event listener="#{sessionHandler.checkLoggedIn}" type="preRenderView" />
    <p:outputLabel value="Ich sollte hier sein" />

</ui:composition>
Geht es. Das neue Tab wird mir angezeigt, ich kann da drauf wechseln, aber es ist eben nur dieser Text abgebildet.
Wenn ich versuche auch die Daten in der Liste zuzugreifen, dann fliegt mir das Ganze scheinbar um die Ohren. Evtl. weiß das Tab nicht, auf welche Daten es zugreifen soll?
 

DaBe1812

Bekanntes Mitglied
So, wollte mich mal zurück melden, nachdem ich das mit Primefaces direkt diskutiert habe. Also die Jungs von Primefaces waren sehr verwirrt darüber, dass ich die Namespaces von p und c vermischt habe. Meine aktuell funktionierende aber optisch eher häßliche Lösung ist damit folgendes:
HTML:
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
    xmlns:c="http://java.sun.com/jsp/jstl/core" template="../layout.xhtml">

    <ui:define name="header">
        ProIPS - Datenpflege
    </ui:define>

    <ui:define name="main">
        
        <h:form id="datenpflegeForm">
            
            <p:growl id="msgs" showDetail="true" skipDetailIfEqualsSummary="true" />

            <div class="card">
                <p:tabView id="pipsTabView" value="#{dataExplorerHandler.openTabList}" var="openTab" activeIndex="#{dataExplorerHandler.activeTabIndex}"
                        dynamic="true" >

                    <p:ajax event="tabClose" listener="#{dataExplorerHandler.onTabClose}" update=":datenpflegeForm:msgs" />

                    <p:tab title="#{openTab.title}" closable="#{openTab.closable}">
                        <p:toolbar rendered="#{openTab.editable}">
                            <p:toolbarGroup>
                                <p:commandButton title="Bearbeiten" icon="pi pi-pencil" styleClass="mr-2" update=":datenpflegeForm" 
                                        action="#{dataExplorerHandler.editRecord(openTab)}" rendered="#{not openTab.editor}" />
                                <p:commandButton title="Speichern" icon="pi pi-save" styleClass="ui-button-help mr-2"  update=":datenpflegeForm"
                                        action="#{dataExplorerHandler.saveRecord(openTab)}" rendered="#{openTab.editor}"/>
                                <p:commandButton type="button" title="Löschen" icon="pi pi-trash" styleClass="ui-button-danger mr-2" />
                            </p:toolbarGroup>
                        </p:toolbar>
                        <h:panelGroup id="searchPanelGroupId" layout="block" rendered="#{openTab.subpage eq 'search'}">
                            <ui:include src="./dataexplorer/search.xhtml" />
                        </h:panelGroup>
                        <h:panelGroup id="realEditorPanelGroupId" layout="block" rendered="#{openTab.subpage eq 'windowsOrderDetail'}">
                            <ui:include src="./dataexplorer/windowsOrderDetail.xhtml" />
                        </h:panelGroup>
                    </p:tab>
                </p:tabView>
            </div>
        </h:form>
    </ui:define>
</ui:composition>
D.h. die Unterseiten sind alle definiert und werden eben bei Bedarf gerendert. Ist unglaublich unschön, aber der c:foreach-Ansatz führt zu ein paar Fehlern, wenn ich z.B. eine Unterseite mit ihren Daten laden möchte, dann droppt die Anwendung einen Fehler, scheinbar beim Zugriff auf die Daten.
 

Ähnliche Java Themen

Neue Themen


Oben