2012-05-13 27 views
5

Pregunté sobre los atributos de paso a través en different question y encontré que podía crear un procesador personalizado para el componente <p:autocomplete> pero el problema es que mi procesador personalizado se usaría para cada p: autocompletar en mi proyecto (en todo el sitio). Por lo tanto, he elegido crear un componente personalizado que extienda org.primefaces.component.autocomplete.AutoComplete y agregue los atributos necesarios al cuadro de texto.Agregar atributos personalizados al componente de autocompletado Primefaces en JSF

Mi idea inicial fue la de añadir un constructor pero no parece funcionar porque el mapa atributo es nulo en este punto:

@FacesComponent("com.mycomponents.SiteSearch") 
public class SiteSearch extends AutoComplete { 

    public SiteSearch() { 
     Map<String,Object> attrs = getAttributes(); 
     attrs.put("x-webkit-speech", null); 
     attrs.put("x-webkit-grammer", "builtin:search"); 
     attrs.put("onwebkitspeechchange", "this.form.submit();"); 
     attrs.put("placeholder", "Enter a Search Term"); 
    } 
} 

Mi otra idea era dejar este componente personalizado vacío (clase vacía) y luego especifique un renderizador personalizado que extienda org.primefaces.component.autocomplete.AutoCompleteRenderer y modifique los atributos allí.

Después de todo lo dicho y hecho, solo necesito una forma de mantener estos atributos separados para este cuadro de texto así que simplemente poner un renderizador personalizado en el p: autocompletar no va a funcionar (a menos que pueda usar renderType = atributo para este p: autocompletar?).

+0

@BalusC alguna idea? – Adam

+0

Estaba viendo series (House MD en este momento). Ten un poco de paciencia :) – BalusC

+0

Haha. No problemas. Creo que cada vez que veo una pregunta de JSF, automáticamente asumo que la tuya será la respuesta sin siquiera mirar. ¿Alguien puede decir ninja JSF? – Adam

Respuesta

18

Si necesita un componente específico que utiliza un representador diferente de <p:autoComplete>, entonces no puede crear un componente personalizado con su propia familia y tipo de componente. Todavía puede ampliar las PrimeFaces AutoComplete (y su procesador) para guardar un código repetitivo.

En el componente personalizado, debe proporcionar getters para esos atributos. También podría especificar configuradores, de esta manera siempre puede anular los valores predeterminados en el lado de la vista. Esos getters/setters deberían a su vez delegar en StateHelper.

Solo hay un pequeño problema con los atributos x-webkit-*. El - es un carácter ilegal en los identificadores de Java. Por lo tanto, debe cambiar el nombre de los getters/setters y cambiar el renderizador de alguna manera, ya que el renderizador estándar confía en que el nombre de la propiedad del componente sea exactamente el mismo que el nombre del atributo de la etiqueta. Update: Entiendo que x-webkit-speech solo debe representarse como está (por lo tanto, no es necesario getter/setter) y que x-webkit-grammer es en realidad un error tipográfico, debería ser x-webkit-grammar.

Así es como el componente SiteSearch puede verse como:

@FacesComponent(SiteSearch.COMPONENT_TYPE) 
public class SiteSearch extends AutoComplete { 

    public static final String COMPONENT_FAMILY = "com.example"; 
    public static final String COMPONENT_TYPE = "com.example.SiteSearch"; 

    private enum PropertyKeys { 
     grammar, onspeechchange, placeholder 
    } 

    @Override 
    public String getFamily() { 
     return COMPONENT_FAMILY; 
    } 

    @Override 
    public String getRendererType() { 
     return SiteSearchRenderer.RENDERER_TYPE; 
    } 

    public String getGrammar() { 
     return (String) getStateHelper().eval(PropertyKeys.grammar, "builtin:search"); 
    } 

    public void setGrammar(String grammar) { 
     getStateHelper().put(PropertyKeys.grammar, grammar); 
    } 

    public String getOnspeechchange() { 
     return (String) getStateHelper().eval(PropertyKeys.onspeechchange, "submit()"); 
    } 

    public void setOnspeechchange(String onspeechchange) { 
     getStateHelper().put(PropertyKeys.onspeechchange, onspeechchange); 
    } 

    public String getPlaceholder() { 
     return (String) getStateHelper().eval(PropertyKeys.placeholder, "Enter a Search Term"); 
    } 

    public void setPlaceholder(String placeholder) { 
     getStateHelper().put(PropertyKeys.placeholder, placeholder); 
    } 

} 

Tenga en cuenta que los captadores tienen todos los valores por defecto especificados. Si el eval() devuelve null, se devolverá el valor predeterminado. También he neutralizado los nombres de los atributos de alguna manera para que puedan ser reutilizados para futuros navegadores que no sean webkit simplemente modificando el renderizador en consecuencia.

Y así es como el SiteSearchRenderer procesador debe ser similar para el componente anterior:

@FacesRenderer(
    componentFamily=SiteSearch.COMPONENT_FAMILY, 
    rendererType=SiteSearchRenderer.RENDERER_TYPE 
) 
public class SiteSearchRenderer extends AutoCompleteRenderer { 

    public static final String RENDERER_TYPE = "com.example.SiteSearchRenderer"; 

    @Override 
    protected void renderPassThruAttributes(FacesContext facesContext, UIComponent component, String[] attrs) throws IOException { 
     ResponseWriter writer = facesContext.getResponseWriter(); 
     writer.writeAttribute("x-webkit-speech", "x-webkit-speech", null); 
     writer.writeAttribute("x-webkit-grammar", component.getAttributes().get("grammar"), "grammar"); 
     writer.writeAttribute("onwebkitspeechchange", component.getAttributes().get("onspeechchange"), "onspeechchange"); 
     writer.writeAttribute("placeholder", component.getAttributes().get("placeholder"), "placeholder"); 
     super.renderPassThruAttributes(facesContext, component, attrs); 
    } 

} 

para usarlo en la vista, que, por supuesto, hay que registrarlo como una etiqueta. Crear un archivo /WEB-INF/my.taglib.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<facelet-taglib 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd" 
    version="2.0" 
> 
    <namespace>http://example.com/ui</namespace> 

    <tag> 
     <tag-name>siteSearch</tag-name> 
     <component> 
      <component-type>com.example.SiteSearch</component-type> 
      <renderer-type>com.example.SiteSearchRenderer</renderer-type> 
     </component> 
    </tag> 
</facelet-taglib> 

Tenga en cuenta que no es necesario un <renderer> en faces-config.xml para esto. La anotación @FacesRenderer puede hacer su trabajo en componentes personalizados reales.Por lo tanto, elimine la entrada <renderer> en faces-config.xml que creó en función de su pregunta anterior.

ahora a JSF que usted tiene una taglib a medida por el siguiente parámetro contexto en web.xml:

<context-param> 
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name> 
    <param-value>/WEB-INF/my.taglib.xml</param-value> 
</context-param> 

Finalmente, puede utilizarlo como sigue:

<html ... xmlns:my="http://example.com/ui"> 
... 
<my:siteSearch /> 

incluso puede especificar adicional atributos que anularán los valores predeterminados establecidos en el componente:

<my:siteSearch grammar="builtin:language" onspeechchange="alert('peek-a-boo')" placeholder="Search" /> 

Para IDE autocompletar en atributos, necesitaría especificar cada uno como un <attribute> por separado en la declaración <tag> en el my.taglib.xml.

+0

Wow. ¡Rock! ¡Gracias! – Adam

+0

De nada. – BalusC

+0

@BalusC, Cómo lograr esto mismo para mi componente personalizado, que se creó usando compoiste como https://stackoverflow.com/questions/44454804/composite-attributes-returns-null-in-jsf-custom-components –

Cuestiones relacionadas