2013-04-05 18 views
7

Sto lavorando con un dashboard dinamico in cui gli utenti possono bloccare e rimuovere gli articoli come preferiscono. Ora ho un problema che voglio aggiungere il componente composito esistente alla vista dal backing bean. Ho cercato di trovare il modo corretto per farlo da Internet, ma finora non ha avuto successo. Ecco la semplice componente composito voglio aggiungere:Creare e aggiungere programmaticamente un componente composito nel bean di supporto

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:cc="http://java.sun.com/jsf/composite" 
     xmlns:ui="http://java.sun.com/jsf/facelets" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:f="http://java.sun.com/jsf/core" 
     xmlns:p="http://primefaces.org/ui" 
     xmlns:composite="http://java.sun.com/jsf/composite"> 
    <!-- INTERFACE --> 
    <cc:interface> 

    </cc:interface> 

    <!-- IMPLEMENTATION --> 
    <cc:implementation> 
     <h:outputText value="TEST"/> 
    </cc:implementation> 
</html> 

Ecco il codice che dovrebbe restituire la componente composito:

public static UIComponent getCompositeComponent(String xhtml, String namespace) { 
    FacesContext fc = FacesContext.getCurrentInstance(); 
    Application app = fc.getApplication(); 
    Resource componentResource = app.getResourceHandler().createResource(xhtml, namespace); 

    UIPanel facet = (UIPanel) app.createComponent(UIPanel.COMPONENT_TYPE); 
    facet.setRendererType("javax.faces.Group"); 
    UIComponent composite = app.createComponent(fc, componentResource); 
    composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, facet); 

    return composite; 
} 

Ed ecco come sto usando la funzione:

Column column = new Column(); 
UIComponent test = HtmlUtil.getCompositeComponent("test.xhtml", "comp"); 
column.getChildren().add(test); 

Ma non viene eseguito il rendering all'interno della colonna. Qualche idea su come questo potrebbe essere fatto? Non voglio seguire il metodo rendered = "# {bean.isThisRendered}" perché non si adatta al mio caso d'uso.

+0

Fuori di interesse (l'argomento è terribilmente male coperto e questo mi avrebbe portato anni avanti luce): Da dove si invocando la 3-liner chiama 'HtmlUtil.getCompositeComponent'? –

risposta

11

Questo codice è incompleto. È necessario utilizzare FaceletContext#includeFacelet() in seguito per includere la risorsa del componente composito nell'implementazione del componente composito. Ecco un metodo di utilità che fa il lavoro. È importante avere il genitore a portata di mano, in quanto è il contesto in cui è necessario creare #{cc} nell'ambito EL. Quindi, anche questo metodo di utilità aggiunge immediatamente il composito come figlio del genitore dato. Inoltre, è importante fornire al componente composito un ID fisso, altrimenti JSF non sarebbe in grado di elaborare alcun componente di form/input/comando all'interno del composito.

public static void includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id) { 
    // Prepare. 
    FacesContext context = FacesContext.getCurrentInstance(); 
    Application application = context.getApplication(); 
    FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY); 

    // This basically creates <ui:component> based on <composite:interface>. 
    Resource resource = application.getResourceHandler().createResource(resourceName, libraryName); 
    UIComponent composite = application.createComponent(context, resource); 
    composite.setId(id); // Mandatory for the case composite is part of UIForm! Otherwise JSF can't find inputs. 

    // This basically creates <composite:implementation>. 
    UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE); 
    implementation.setRendererType("javax.faces.Group"); 
    composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation); 

    // Now include the composite component file in the given parent. 
    parent.getChildren().add(composite); 
    parent.pushComponentToEL(context, composite); // This makes #{cc} available. 
    try { 
     faceletContext.includeFacelet(implementation, resource.getURL()); 
    } catch (IOException e) { 
     throw new FacesException(e); 
    } finally { 
     parent.popComponentFromEL(context); 
    } 
} 

Così, nel vostro esempio particolare, usarlo come segue:

includeCompositeComponent(column, "comp", "test.xhtml", "someUniqueId"); 
+0

Molto interessante! È possibile utilizzare questo metodo (forse un po 'modificato) per includere componenti esterni? Invece di utilizzare una risorsa esistente vorrei includere componenti che non sono definiti all'interno dell'applicazione. – fnst

+1

@fnst: è possibile se necessario controllare la gestione delle risorse con un gestore di risorse personalizzato. Finché alla fine si finisce con un 'URL' valido, può fondamentalmente puntare a tutto (compresi' file: // ',' http: // ', ecc. E persino protocolli personalizzati in modo che, ad esempio, l'accesso al DB sia teoricamente possibile) . – BalusC

+0

Grazie per la tua risposta, devi provarlo :) È anche possibile aggiungere espressioni di valore come attributi per i componenti compositi? – drodil

Problemi correlati