8 votes

Création et ajout programmés d'un composant composite dans le backing bean.

Je travaille avec un tableau de bord dynamique où les utilisateurs peuvent épingler et supprimer des éléments comme ils le souhaitent. J'ai maintenant un problème : je veux ajouter un composant composite existant à la vue depuis le backing bean. J'ai essayé de trouver la bonne façon de le faire sur Internet, mais sans succès jusqu'à présent. Voici le composant composite simple que je veux ajouter :

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

Voici le code qui devrait renvoyer le composant composite :

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

Et voici comment j'utilise la fonction :

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

Mais rien n'est rendu à l'intérieur de la colonne. Avez-vous une idée de la façon dont cela pourrait être fait ? Je ne veux pas utiliser la méthode rendered="#{bean.isThisRendered}" car elle ne correspond pas à mon cas d'utilisation.

11voto

BalusC Points 498232

Ce code est incomplet. Vous devez utiliser FaceletContext#includeFacelet() après pour inclure la ressource du composant composite dans l'implémentation du composant composite. Voici une méthode utilitaire qui fait le travail. Il est important d'avoir le parent à portée de main, car il s'agit du contexte dans lequel l'élément #{cc} doit être créé dans la portée de l'EL. Cette méthode utilitaire ajoute donc immédiatement le composite en tant qu'enfant du parent donné. En outre, il est important de donner au composant composite un ID fixe, sinon JSF ne sera pas en mesure de traiter les composants formulaire/saisie/commande à l'intérieur du composite.

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

Ainsi, dans votre exemple particulier, utilisez-le comme suit :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X