2012-05-13 6 views
5

ich durch Attribut in einem different question Pass gefragt und fand ich einen benutzerdefinierten Renderer für die <p:autocomplete> Komponente schaffen könnte, aber das Problem ist, meine benutzerdefinierten Renderer für jedes p verwendet werden würden: die automatische Vervollständigung in meinem Projekt (siteweit). Deshalb habe ich gewählt, eine benutzerdefinierte Komponente zu erstellen, die org.primefaces.component.autocomplete.AutoComplete erweitert und die erforderlichen Attribute zu dem Textfeld hinzufügt.Hinzufügen von benutzerdefinierten Attributen zu Primefaces automatischer Vervollständigung Komponente in JSF

Mein erster Gedanke war, einen Konstruktor hinzufügen, aber es scheint nicht zu funktionieren, weil das Attribut Karte an dieser Stelle null ist:

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

Mein anderer Gedanke war, lassen Sie diese benutzerdefinierte Komponente leer (leere Klasse) und geben Sie dann einen benutzerdefinierten Renderer an, der org.primefaces.component.autocomplete.AutoCompleteRenderer erweitert und die Attribute dort ändert.

Nachdem alles gesagt und getan ist, brauche ich nur einen Weg, um diese Attribute getrennt zu diesem einen Textfeld zu halten, so nur einen benutzerdefinierten Renderer auf dem p: autoComplete wird nicht funktionieren (es sei denn vielleicht kann ich renderType = Attribut für dieses eine p: autoComplete?).

+0

@BalusC irgendwelche Ideen? – Adam

+0

War gerade Serie (House MD gerade). Hab ein bisschen Geduld :) – BalusC

+0

Haha. Keine Probleme. Ich denke immer, wenn ich eine JSF Frage sehe, nehme ich einfach automatisch an, dass deine Antwort die Antwort sein wird, ohne überhaupt nachzusehen. Kann jemand JSF Ninja sagen? – Adam

Antwort

18

Wenn Sie eine bestimmte Komponente benötigen, die einen anderen Renderer als <p:autoComplete> verwendet, können Sie nicht wirklich eine benutzerdefinierte Komponente mit einer eigenen Familie und einem eigenen Komponententyp erstellen. Sie können die PrimeFaces AutoComplete (und ihren Renderer) immer noch erweitern, um einige Codebeispiele zu speichern.

In der benutzerdefinierten Komponente müssen Getter für diese Attribute bereitgestellt werden. Sie können ebenso gut Setter angeben. Auf diese Weise können Sie die Standardwerte auf der Sichtseite immer überschreiben. Diese Getter/Setter sollten wiederum an StateHelper delegieren.

Es gibt nur ein kleines Problem mit x-webkit-* Attributen. Die ist ein ungültiges Zeichen in Java-Bezeichnern. Daher müssen Sie die Getter/Setter umbenennen und den Renderer etwas ändern, da der Standard-Renderer davon abhängig ist, dass der Name der Komponenteneigenschaft genau dem Namen des Tag-Attributs entspricht. Update: Ich verstehe, dass x-webkit-speech nur so gerendert werden soll (so, kein Getter/Setter notwendig) und dass x-webkit-grammer eigentlich ein Tippfehler ist, sollte es x-webkit-grammar sein.

Hier ist, wie die SiteSearch Komponente aussehen kann:

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

} 

Bitte beachten Sie, dass die Getter alle Standardwerte angegeben haben. Wenn eval()null zurückgibt, wird stattdessen der Standardwert zurückgegeben. Ich habe auch die Attributnamen etwas neutralisiert, so dass sie für zukünftige Browser ohne Webkit wiederverwendet werden können, indem ich den Renderer entsprechend modifiziere.

Und hier ist, wie die SiteSearchRenderer Renderer wie für die obige Komponente aussehen sollen:

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

} 

Um es in der Ansicht zu verwenden, wir brauchen natürlich es als Tag zu registrieren. Erstellen Sie eine Datei /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> 

Beachten Sie, dass Sie keine <renderer> in faces-config.xml dafür mehr benötigen. Die @FacesRenderer Annotation kann einfach ihre Arbeit an echten benutzerdefinierten Komponenten erledigen.Entfernen Sie also den <renderer> Eintrag in faces-config.xml, den Sie basierend auf Ihrer vorherigen Frage erstellt haben.

Jetzt JSF sagen, dass Sie eine benutzerdefinierte taglib durch den folgenden Zusammenhang param in web.xml haben:

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

Schließlich können Sie es wie folgt verwendet werden:

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

Sie können sogar angeben, zusätzliche Attribute, die die in der Komponente festgelegten Voreinstellungen überschreiben:

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

Für die automatische Vervollständigung der IDE in Attributen müssen Sie alle als separate <attribute> in der <tag> Deklaration in my.taglib.xml angeben.

+0

Wow. Du schaukelst! Vielen Dank! – Adam

+0

Gern geschehen. – BalusC

+0

@BalusC, Wie dies auch für meine benutzerdefinierte Komponente, die mit Composte wie https://stackoverflow.com/questions/44454804/composite-attributes-returns-null-in-jsf-custom-components erstellt erstellt achive –