Saltar al contenido

Cómo crear campos de formulario JSF dinámicos

Ya no tienes que buscar más por otros sitios ya que has llegado al sitio correcto, contamos con la respuesta que buscas pero sin problemas.

Solución:

Dado que el origen en realidad no es XML, sino un Javabean, y la otra respuesta no merece ser editada en un sabor totalmente diferente (aún puede ser útil para futuras referencias de otros), agregaré otra respuesta basada en un Origen de Java.


Veo básicamente tres opciones cuando el origen es un Javabean.

  1. Hacer uso de JSF rendered attribute o incluso JSTL / etiquetas para renderizar o construir condicionalmente los componentes deseados. A continuación se muestra un ejemplo usando rendered attribute:

    
        

    Se puede encontrar un ejemplo del enfoque JSTL en ¿Cómo hacer una cuadrícula de componente compuesto JSF? No, JSTL no es en absoluto una “mala práctica”. Este mito es un vestigio de la era JSF 1.xy continúa demasiado tiempo porque los principiantes no entendían claramente el ciclo de vida y los poderes de JSTL. Al grano, puede usar JSTL solo cuando el modelo detrás #bean.fields como en el fragmento de código anterior, nunca cambia durante al menos el alcance de la vista JSF. Consulte también JSTL en JSF2 Facelets … ¿tiene sentido? En cambio, usando binding a una propiedad de frijol sigue siendo una “mala práctica”.

    En cuanto a la

    , realmente no importa qué componente iterativo use, incluso puede usar como en su pregunta inicial, o un componente iterativo específico de la biblioteca de componentes, como o . Refactorice, si es necesario, la gran parte del código en un archivo de inclusión o etiqueta.

    En cuanto a la recopilación de los valores enviados, el #bean.values debería apuntar a un Map que ya está precreada. A HashMap es suficiente. Es posible que desee rellenar previamente el mapa en caso de que haya controles que puedan establecer varios valores. A continuación, debe rellenarlo previamente con un List como valor. Tenga en cuenta que espero el Field#getType() ser un enum ya que eso facilita el procesamiento en el lado del código Java. A continuación, puede utilizar un switch declaración en lugar de una desagradable if/else cuadra.


  2. Cree los componentes mediante programación en un postAddToView oyente de eventos:

    
        
    
    

    Con:

    public void populateForm(ComponentSystemEvent event) 
        HtmlForm form = (HtmlForm) event.getComponent();
        for (Field field : fields) 
            switch (field.getType())  // It's easiest if it's an enum.
                case TEXT:
                    UIInput input = new HtmlInputText();
                    input.setId(field.getName()); // Must be unique!
                    input.setValueExpression("value", createValueExpression("#bean.values['" + field.getName() + "']", String.class));
                    form.getChildren().add(input);
                    break;
                case SECRET:
                    UIInput input = new HtmlInputSecret();
                    // etc...
            
        
    
    

    (nota: NO cree el HtmlForm ¡tú mismo! use el creado por JSF, este nunca es null)

    Esto garantiza que el árbol se rellene exactamente en el momento correcto, mantiene a los captadores libres de lógica empresarial y evita posibles problemas de “ID de componente duplicado” cuando #bean está en un alcance más amplio que el alcance de la solicitud (por lo que puede usar de manera segura, por ejemplo, un bean con alcance de vista aquí), y mantiene el bean libre de UIComponent propiedades que, a su vez, evitan posibles problemas de serialización y pérdidas de memoria cuando el componente se mantiene como propiedad de un bean serializable.

    Si todavía está en JSF 1.x donde no está disponible, en su lugar, vincule el componente de formulario a una solicitud (¡no a una sesión!) Bean con ámbito a través de binding

    
    

    Y luego rellénelo perezosamente en el getter del formulario:

    public HtmlForm getForm() 
        if (form == null) 
            form = new HtmlForm();
            // ... (continue with code as above)
        
        return form;
    
    

    Cuando usas binding, es muy importante comprender que los componentes de la interfaz de usuario tienen básicamente un alcance de solicitud y no deben asignarse como una propiedad de un bean en un alcance más amplio. Consulte también ¿Cómo funciona el ‘enlace’ attribute trabajar en JSF? ¿Cuándo y cómo se debe utilizar?


  3. Cree un componente personalizado con un renderizador personalizado. No voy a publicar ejemplos completos, ya que es mucho código que, después de todo, sería un lío muy ajustado y específico de la aplicación.


  4. Los pros y los contras de cada opción deben estar claros. Va desde el más fácil y de mejor mantenimiento hasta el más duro y de menor mantenimiento y, posteriormente, también desde el menos reutilizable hasta el mejor reutilizable. Depende de usted elegir lo que mejor se adapte a sus necesidades funcionales y su situación actual.

    Debe notarse que hay absolutamente nada cual es solamente posible en Java (forma # 2) e imposible en XHTML + XML (forma # 1). Todo es posible en XHTML + XML tan bien como en Java. Muchos principiantes subestiman XHTML + XML (particularmente y JSTL) en la creación dinámica de componentes y piensan incorrectamente que Java sería la “única” forma, mientras que generalmente solo termina en un código frágil y confuso.

    Si el origen es XML, sugiero optar por un enfoque completamente diferente: XSL. Facelets está basado en XHTML. Puede usar XSL fácilmente para pasar de XML a XHTML. Esto es factible con un poco decente. Filter que se activa antes de que JSF esté funcionando.

    Aquí hay un ejemplo de inicio.

    persons.xml

    
    
        
            one
            1
        
        
            two
            2
        
        
            three
            3
        
    
    

    persons.xsl

    
    
    
    
        
    
        
            
            
                Persons
                
                    
                        
                            
                            
                            
                            
                        
                    
                
            
            
        
    
    

    JsfXmlFilter que está mapeado en de El FacesServlet y asume que el FacesServlet sí mismo está mapeado en un de *.jsf.

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException
    
        HttpServletRequest r = (HttpServletRequest) request;
        String rootPath = r.getSession().getServletContext().getRealPath("/");
        String uri = r.getRequestURI();
        String xhtmlFileName = uri.substring(uri.lastIndexOf("/")).replaceAll("jsf$", "xhtml"); // Change this if FacesServlet is not mapped on `*.jsf`.
        File xhtmlFile = new File(rootPath, xhtmlFileName);
    
        if (!xhtmlFile.exists())  // Do your caching job.
            String xmlFileName = xhtmlFileName.replaceAll("xhtml$", "xml");
            String xslFileName = xhtmlFileName.replaceAll("xhtml$", "xsl");
            File xmlFile = new File(rootPath, xmlFileName);
            File xslFile = new File(rootPath, xslFileName);
            Source xmlSource = new StreamSource(xmlFile);
            Source xslSource = new StreamSource(xslFile);
            Result xhtmlResult = new StreamResult(xhtmlFile);
    
            try 
                Transformer transformer = TransformerFactory.newInstance().newTransformer(xslSource);
                transformer.transform(xmlSource, xhtmlResult);
             catch (TransformerException e) 
                throw new RuntimeException("Transforming failed.", e);
            
        
    
        chain.doFilter(request, response);
    
    

    Ejecutado por http://example.com/context/persons.jsf y este filtro se activará y transformará persons.xml para persons.xhtml utilizando persons.xsl y finalmente poner persons.xhtml allí donde JSF espera que esté.

    Es cierto que XSL tiene un poco de curva de aprendizaje, pero IMO es la herramienta adecuada para el trabajo, ya que la fuente es XML y el destino también está basado en XML.

    Para hacer el mapeo entre el formulario y el bean administrado, simplemente use un Map. Si nombra los campos de entrada así

    
    
    
    ...
    

    Los valores enviados estarán disponibles por Map keys field1, field2, field3etc.

    Si estás contento con lo expuesto, tienes la opción de dejar un ensayo acerca de qué le añadirías a este artículo.

    ¡Haz clic para puntuar esta entrada!
    (Votos: 2 Promedio: 4.5)



    Utiliza Nuestro Buscador

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    Respuestas a preguntas comunes sobre programacion y tecnología