2011-07-28 14 views
11

Estoy intentando escribir un representador que procese el atributo placeholder en un componente <h:inputText>. Me dirigí a este camino después de leer JSF 2.0 strips out needed HTML5 attributes y parece correcto. Aquí está mi costumbre procesadorAgregar soporte de atributo personalizado (HTML5) al componente JSF 2.0 UIInput

public class InputRenderer extends com.sun.faces.renderkit.html_basic.TextRenderer{ 

    @Override 
    public void encodeBegin(FacesContext context, UIComponent component) 
    throws IOException { 
     System.out.println("Rendering :"+component.getClientId()); 

     String placeholder = (String)component.getAttributes().get("placeholder"); 
     if(placeholder != null) { 
      ResponseWriter writer = context.getResponseWriter(); 
      writer.writeAttribute("placeholder", placeholder, "placeholder"); 
     } 

     super.encodeBegin(context, component); 

    } 


    @Override 
    public void decode(FacesContext context, UIComponent component) { 
     super.decode(context, component); 
    } 

    @Override 
    public void encodeEnd(FacesContext context, UIComponent component) 
    throws IOException { 
     super.encodeEnd(context, component); 
    } 
} 

Y este procesador se ha registrado en las caras de los config como

<render-kit> 
    <renderer> 
     <component-family>javax.faces.Input</component-family> 
     <renderer-type>javax.faces.Text</renderer-type> 
     <renderer-class>com.example.renderer.InputRenderer</renderer-class> 
    </renderer> 
</render-kit> 

Esto pone titulado bien, no hay problemas.

Mi intención es procesar el atributo placeholder, insértelo y luego delegue el procesamiento en super. Mi código anterior no funciona porque estoy insertando el atributo en un lugar equivocado. Debe insertarse después de que se haya ejecutado writer.startElement('input'). Sin embargo, startElement debe estar sucediendo en algún lugar del método encodeBegin() del super. Entonces, ¿cómo puedo insertar un atributo personalizado ('marcador de posición' en este caso) y luego continuar el flujo de ejecución?

NB: El código anterior agrega un atributo placeholder pero no al componente de entrada que pretendo, lo escribe en el padre de la Entrada (ya que estoy tratando de escribir un atributo antes de que el componente sea realmente escrito en la secuencia, aplica el atributo al componente actual)

Respuesta

19

Esta es mi manera. Agregué marcadores de posición y atributos de tema de datos. Si desea agregar más atributos, solo debe agregar su nombre a la matriz de atributos.

import javax.faces.component.UIComponent; 
import javax.faces.context.FacesContext; 
import javax.faces.context.ResponseWriter; 

import com.sun.faces.renderkit.html_basic.TextRenderer; 

public class InputRender extends TextRenderer { 

    @Override 
    protected void getEndTextToRender(FacesContext context, 
      UIComponent component, 
      String currentValue) 
    throws java.io.IOException{ 

     String [] attributes = {"placeholder","data-theme"}; 

     ResponseWriter writer = context.getResponseWriter(); 

     for(String attribute : attributes) 
     { 
      String value = (String)component.getAttributes().get(attribute); 
      if(value != null) {        
       writer.writeAttribute(attribute, value, attribute); 
      } 
     } 

     super.getEndTextToRender(context, component, currentValue); 

    } 

} 

Debe agregar esto al archivo faces-config.xml.

<render-kit> 
    <renderer> 
     <component-family>javax.faces.Input</component-family> 
     <renderer-type>javax.faces.Text</renderer-type> 
     <renderer-class>your.package.InputRenderer</renderer-class> 
    </renderer> 
</render-kit> 
+0

¡Esta es, de lejos, la respuesta más práctica y la mejor! :) – Nikhil

+1

Gracias por la respuesta y si bien esta es una respuesta justa, el código tiene un error. El retorno de get (atributo) es un Objeto, que puede ser un Booleano (considere el atributo 'required' por ejemplo). Elimine por completo la hebra (String) y establezca return-type como Object. –

+1

Tenga en cuenta que esto no funciona con '' padre con '' hijos. JSF coloca el atributo 'required' en el elemento' 'en lugar del elemento' '. ¿Dije que amo JSF? –

6

Puede anular el método startElement ResponseWriters, ese método solo se llama una vez y luego puede restaurar el objeto original del redactor de respuesta.

import javax.faces.context.*; 
import java.io.IOException; 

public class InputRenderer extends com.sun.faces.renderkit.html_basic.TextRenderer{ 

     // Put all of the attributes you want to render here... 
     private static final String[] ATTRIBUTES = {"required","placeholder"}; 

    @Override 
    protected void getEndTextToRender(FacesContext context, 
      UIComponent component, String currentValue) throws IOException { 
     final ResponseWriter originalResponseWriter = context.getResponseWriter(); 
     context.setResponseWriter(new ResponseWriterWrapper() { 

      @Override 
// As of JSF 1.2 this method is now public. 
      public ResponseWriter getWrapped() { 
       return originalResponseWriter; 
      } 

      @Override 
      public void startElement(String name, UIComponent component) 
        throws IOException { 
       super.startElement(name, component); 
if ("input".equals(name)) { 
    for (String attribute : ATTRIBUTES) 
    { 
    Object value = component.getAttributes().get(attribute); 
    if (value != null) 
    { 
     super.writeAttribute(attribute,value,attribute); 
} 
    } 
} 
     }); 
     super.getEndTextToRender(context, component, currentValue); 
     context.setResponseWriter(originalResponseWriter); // Restore original writer. 
    } 



} 
+0

Lo anterior funciona mejor (aunque faltan algunas importaciones, corregí getWrapped() como en JSF 1.2 es ahora pública, etc.). Creo que esta es la mejor respuesta. También es probable que sea mejor utilizar if ("constante" .equals (valor)) que maneja la verificación nula, ya que la constante nunca será nula pero no arrojará un NPE. Ahora, oficialmente, desprecio la convolución de JSF como una alternativa de alguna manera mejor, pero aprecio todos los buenos comentarios aquí (gracias a Joel por respaldar StackOverflow). –

2

Y para anular para MyFaces 2.0.8+

package com.hsop.abc.eld; 

import java.io.IOException; 

import javax.faces.component.UIComponent; 
import javax.faces.context.FacesContext; 
import javax.faces.context.ResponseWriter; 

import org.apache.myfaces.renderkit.html.HtmlTextRenderer; 

public class InputRenderer extends HtmlTextRenderer 
{ 
    @Override 
    protected void renderInputBegin(FacesContext context, UIComponent component) 
      throws IOException 
    { 
     // TODO Auto-generated method stub 
     super.renderInputBegin(context, component); 

    Object placeholder = component.getAttributes().get("placeholder"); 
    if(placeholder != null) { 
     ResponseWriter writer = context.getResponseWriter(); 
     writer.writeAttribute("placeholder", placeholder, "placeholder"); 
    } 

    } 
} 
+0

Para aquellos que leen demasiado rápido, también necesita la etiqueta desde arriba en su archivo faces-config.xml. –

Cuestiones relacionadas