2013-04-05 17 views
7

Pracuję z dynamicznym pulpitem, na którym użytkownicy mogą przypinać i usuwać elementy według własnego uznania. Teraz mam problem, że chcę dodać istniejący komponent kompozytowy do widoku z komponentu bean. Próbowałem znaleźć prawidłowy sposób na zrobienie tego z internetu, ale jak dotąd nie udało się. Oto prosty składnik kompozytu chcę dodać:Programowe tworzenie i dodawanie komponentu kompozytowego w komponencie bean fasoli

<?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> 

Oto kod, który powinien wrócić zespolonej:

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; 
} 

A oto jak używam funkcji:

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

Ale nic nie jest renderowane wewnątrz kolumny. Jakieś pomysły, jak to zrobić? Nie chcę używać metody rendered = "# {bean.isThisRendered}", ponieważ nie pasuje ona do mojego przypadku użycia.

+0

Spośród zainteresowania (wątek jest strasznie źle pokryta, a to przyniesie mi lata naprzód lekkie): Gdzie jesteś Wywoływanie 3-liniowe wywoływanie 'HtmlUtil.getCompositeComponent'? –

Odpowiedz

11

Ten kod jest niekompletny. Następnie należy użyć FaceletContext#includeFacelet(), aby uwzględnić składnik złożony w implementacji komponentu kompozytowego. Oto metoda użyteczności, która wykonuje zadanie. Ważne jest, aby mieć rodzica na ręce, ponieważ jest to kontekst, w którym należy utworzyć #{cc} w zakresie EL. Tak więc ta metoda użyteczna również natychmiast dodaje kompozyt jako dziecko danego rodzica. Ponadto ważne jest, aby nadać komponentowi kompozytowemu stały identyfikator, w przeciwnym razie JSF nie byłby w stanie przetworzyć żadnych komponentów formuły/wejścia/polecenia wewnątrz kompozytu.

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); 
    } 
} 

więc w konkretnym przykładzie, użyj go w następujący sposób:

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

Bardzo interesujące! Czy możliwe jest użycie tej metody (może trochę zmienionej) do włączenia komponentów zewnętrznych? Zamiast korzystania z istniejącego zasobu chciałbym uwzględnić komponenty, które nie zostały zdefiniowane w aplikacji. – fnst

+1

@ fnst: Możesz w razie potrzeby sterować obsługą zasobów za pomocą niestandardowej procedury obsługi zasobów. Dopóki ostatecznie otrzymasz poprawny "URL", może on w zasadzie wskazywać na wszystko (w tym 'file: //', 'http: //', itd., A nawet niestandardowe protokoły, aby np. Dostęp do bazy danych był teoretycznie możliwy) . – BalusC

+0

Dziękuję za odpowiedź, musicie spróbować tego :) Czy jest również możliwe dodawanie wyrażeń wartości jako atrybutów dla komponentów kompozytowych? – drodil

Powiązane problemy