2012-05-13 19 views
5

Ho chiesto informazioni sugli attributi di passaggio in un different question e ho scoperto che potevo creare un renderizzatore personalizzato per il componente <p:autocomplete> ma il problema è il mio rendering personalizzato utilizzato per ogni p: completamento automatico nel mio progetto (in tutto il sito). Pertanto ho scelto di creare un componente personalizzato che estende org.primefaces.component.autocomplete.AutoComplete e aggiunge gli attributi necessari alla casella di testo.Aggiunta di attributi personalizzati al componente di completamento di Primefaces in JSF

Il mio primo pensiero è stato quello di aggiungere un costruttore, ma non sembra funzionare perché la mappa di attributo è nullo, a questo 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"); 
    } 
} 

altro mio pensiero è stato lasciare questo componente personalizzato vuota (classe vuoto) e quindi specificare un renderizzatore personalizzato che si estende org.primefaces.component.autocomplete.AutoCompleteRenderer e modificare gli attributi lì.

Dopo tutto è detto e fatto, ho solo bisogno di un modo per mantenere questi attributi separare in questa sezione un testo quindi basta mettere un renderer personalizzato sul p: completamento automatico non è andare a lavorare (a meno che forse posso usare renderType = attributo per questo p: autoComplete?).

+0

@BalusC qualche idea? – Adam

+0

Stavo guardando serie (House MD in questo momento). Abbi un po 'di pazienza :) – BalusC

+0

Haha. Non problemi Penso che ogni volta che vedo una domanda JSF automaticamente presumo che la tua sarà la risposta senza nemmeno guardare. Qualcuno può dire JSF ninja? – Adam

risposta

18

Se è necessario un componente specifico che utilizza un renderer diverso da <p:autoComplete>, non è possibile aggirare la creazione di un componente personalizzato con la propria famiglia e il tipo di componente. È ancora possibile estendere PrimeFaces AutoComplete (e il suo renderer) per salvare qualche codice boilerplate.

Nel componente personalizzato, è necessario fornire getter per tali attributi. Puoi anche specificare setter, in questo modo puoi sempre ignorare i valori predefiniti dal lato vista. Questi getter/setter dovrebbero a loro volta delegare a StateHelper.

C'è solo un piccolo problema con gli attributi x-webkit-*. - è un carattere non valido negli identificatori Java. Pertanto, è necessario rinominare i getter/setter e modificare il renderer in qualche modo poiché il renderer standard si basa sul nome della proprietà del componente esattamente uguale al nome dell'attributo del tag. Aggiornamento: ho capito che x-webkit-speech deve essere visualizzato come è (quindi, nessun getter/setter necessario) e che x-webkit-grammer è in realtà un errore di battitura, dovrebbe essere x-webkit-grammar.

Ecco come la componente SiteSearch può apparire come:

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

} 

Si prega di notare che i getter hanno tutti i valori predefiniti specificati. Se eval() restituisce null, verrà restituito il valore predefinito. Ho anche neutralizzato un po 'i nomi degli attributi in modo che possano essere riutilizzati per qualsiasi futuro browser non Webkit semplicemente modificando il renderer di conseguenza.

Ed ecco come il renderer SiteSearchRenderer dovrebbe essere simile per la componente di cui sopra:

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

} 

di utilizzarlo in vista, abbiamo naturalmente bisogno di registrarlo come un tag. Creare un file /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> 

Si noti che non è necessario un <renderer> in faces-config.xml per questo più. L'annotazione @FacesRenderer può fare il proprio lavoro solo su componenti personalizzati reali.Quindi rimuovi la voce faces-config.xml che hai creato in base alla tua domanda precedente.

Ora dirà JSF che hai un taglib personalizzato dal seguente contesto param in web.xml:

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

Infine è possibile utilizzarlo come segue:

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

Si può anche specificare ulteriori attributi che sovrascrivono i valori predefiniti impostati nel componente:

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

Per il completamento automatico IDE sugli attributi, è necessario specificarne uno come numero separato nella dichiarazione <tag> nello my.taglib.xml.

+0

Wow. Sei forte! Grazie! – Adam

+0

Prego. – BalusC

+0

@BalusC, Come ottenere questo stesso per il mio componente personalizzato, che ha creato utilizzando compoiste come dato https://stackoverflow.com/questions/44454804/composite-attributes-returns-null-in-jsf-custom-components –

Problemi correlati