2012-08-16 3 views
8

Ich habe das an mehreren Stellen in meinem Webapp, um Konstrukt folgenden bedingt Seite Fragmente abhängig von einigen Aktionen zu machen:Überspringen der Ausführung <ui:include> wenn Eltern UI-Komponente nicht wiedergegeben wird

<h:panelGroup rendered="#{managedBean.serviceSelected == 'insurance'}"> 
    <ui:include src="/pages/edocket/include/service1.xhtml" /> 
</h:panelGroup> 

ich bemerkt habe, dass die <ui:include> wird auch dann ausgeführt, wenn das Attribut renderedfalse auswertet. Dies erzeugt unnötigerweise alle mit der Datei service1.xhtml assoziierten Backing-Beans, die enthalten sind.

Wie kann ich die Ausführung der <ui:include> überspringen, wenn die übergeordnete UI-Komponente nicht gerendert wird, so dass nicht alle diese Backing-Beans unnötigerweise erstellt werden?

Antwort

9

Leider ist dies von Entwurf. Die <ui:include> wird während der Ansichtserstellungszeit als Taghandler ausgeführt, während das Attribut rendered während der Renderzeit der Ansicht ausgewertet wird. Dies kann besser durch sorgfältiges Lesen Sie diese Antwort und Ersetzen „JSTL“ mit „<ui:include>“ zu verstehen: JSTL in JSF2 Facelets... makes sense?

Es gibt mehrere Möglichkeiten, dies zu lösen, je nach konkreter funktionale Anforderung:

  1. Verwenden Sie einen Blick Build-Zeit-Tag wie <c:if> anstelle von <h:panelGroup>. Dies hat jedoch Auswirkungen auf die #{managedBean}. Es kann nicht im View-Bereich sein und sollte seine Arbeit basierend auf HTTP-Anforderungsparametern erledigen. Genau diese HTTP-Anforderungsparameter sollten auch in nachfolgenden Anforderungen (z. B. <f:param>, includeViewParams usw.) beibehalten werden, damit sie beim Wiederherstellen der Ansicht nicht unterbrochen werden.

  2. <ui:include> Ersetzen durch eine benutzerdefinierte UIComponent, die während des FaceletContext#includeFacelet()UIComponent#encodechildren() Methode aufruft. Bisher existiert keine solche Komponente in einer der vorhandenen Bibliotheken. Aber ich kann sagen, dass ich bereits eine solche Erweiterung für OmniFaces im Auge habe und es funktioniert so intuitiv wie hier bei meiner Testumgebung (mit Mojarra). Hier ist ein Kick-off Beispiel:

    @FacesComponent(Include.COMPONENT_TYPE) 
    public class Include extends UIComponentBase { 
    
        public static final String COMPONENT_TYPE = "com.example.Include"; 
        public static final String COMPONENT_FAMILY = "com.example.Output"; 
    
        private enum PropertyKeys { 
         src; 
        } 
    
        @Override 
        public String getFamily() { 
         return COMPONENT_FAMILY; 
        } 
    
        @Override 
        public boolean getRendersChildren() { 
         return true; 
        } 
    
        @Override 
        public void encodeChildren(FacesContext context) throws IOException { 
         getChildren().clear(); 
         FaceletContext faceletContext = ((FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY)); 
         faceletContext.includeFacelet(this, getSrc()); 
         super.encodeChildren(context); 
        } 
    
        public String getSrc() { 
         return (String) getStateHelper().eval(PropertyKeys.src); 
        } 
    
        public void setSrc(String src) { 
         getStateHelper().put(PropertyKeys.src, src); 
        } 
    
    } 
    
+0

Hallo, Danke für Ihre Antwort BaluSC. Aber ich kann die Antwort nicht verstehen. Wo müssen wir diese Komponente deklarieren und wie man sie benutzt. –

+0

Hallo Balusc, nach dem Hinzufügen der Komponente ist das Überspringen von Include perfekt. Aber wenn es erforderlich ist, einbezogen zu werden, schlägt diese Zeit fehl. Ich werde die Ausnahme FYI einfügen. –

+0

Wurde das schon in Omnifaces aufgenommen, BalusC? –

6

Verwendung bedingter Ausdruck als ui: include src:

<h:panelGroup> 
    <ui:include 
     src="#{managedBean.serviceSelected == 'insurance' ? 
      '/pages/edocket/include/service1.xhtml' 
      : 
      '/pages/empty.xhtml'}" 
    /> 
</h:panelGroup> 
Verwandte Themen