2012-05-13 17 views
5

Zapytałem o przesłanie atrybutów w different question i odkryłem, że mogę utworzyć niestandardowy renderer dla komponentu <p:autocomplete>, ale problem jest taki, że mój niestandardowy renderer byłby używany dla każdego p: autouzupełniania w moim projekt (dla całej witryny). Dlatego wybrałem tworzenie niestandardowego komponentu, który rozszerza org.primefaces.component.autocomplete.AutoComplete i dodaje niezbędne atrybuty do pola tekstowego.Dodawanie niestandardowych atrybutów do elementów pierwotnych Komponent autouzupełniania w JSF

Moją pierwszą myślą było, aby dodać konstruktora, ale nie wydaje się działać, ponieważ mapa atrybut jest null w tym momencie:

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

Moja druga myśl była opuścić ten niestandardowy składnik pusty (klasy) a następnie określ niestandardowy renderer, który rozszerza org.primefaces.component.autocomplete.AutoCompleteRenderer i zmodyfikuj tamte atrybuty.

Po tym wszystkim, co powiedziałem i zrobiłem, po prostu potrzebuję sposobu, aby zachować te atrybuty oddzielnie od tego jednego pola tekstowego, więc samo wstawienie niestandardowego renderera na p: autoComplete nie zadziała (chyba że będę mógł używać renderType = atrybut dla tego p: autoComplete?).

+0

@BalusC jakieś pomysły? – Adam

+0

Oglądałem serię (House MD teraz). Trochę cierpliwości :) – BalusC

+0

Haha. Nie problemy. Wydaje mi się, że za każdym razem, gdy widzę pytanie o JSF, automatycznie zakładam, że twoja odpowiedź stanie się bezowocna. Czy ktoś może powiedzieć ninja JSF? – Adam

Odpowiedz

18

Jeśli potrzebujesz konkretnego komponentu, który używa innego renderera niż <p:autoComplete>, to naprawdę nie możesz obejść tworzenia niestandardowego komponentu z własną rodziną i typem komponentu. Nadal można po prostu rozszerzyć PrimeFaces AutoComplete (i jego renderer), aby zapisać jakiś kod na płycie głównej.

W komponencie niestandardowym należy podać metodę pobierającą dla tych atrybutów. Możesz równie dobrze określić setery, w ten sposób zawsze możesz zastąpić wartości domyślne od strony widoku. Te podmioty pobierające/ustawiające powinny z kolei delegować na StateHelper.

Jest tylko mały problem z atrybutami x-webkit-*. - jest niedozwolonym znakiem w identyfikatorach Java. Musisz więc zmienić nazwy modułów pobierających/ustawiających i zmienić renderer, ponieważ standardowy renderer opiera się na nazwie właściwości komponentu, która jest dokładnie taka sama, jak nazwa atrybutu tagu. Aktualizacja: Rozumiem, że x-webkit-speech powinien być renderowany w niezmienionej formie (więc nie jest konieczny żaden program pobierający/ustawiający), a to, że x-webkit-grammer jest w rzeczywistości literówką, powinno być x-webkit-grammar.

Oto jak składnik SiteSearch może wyglądać następująco:

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

} 

Należy pamiętać, że w pozyskiwaniu wszystkie wartości domyślne określone. Jeśli eval() zwraca null, zamiast tego zostanie zwrócona wartość domyślna. Zneutralizowałem też nieco nazwy atrybutów, aby można je było ponownie wykorzystać w przyszłych przeglądarkach innych niż webkit, modyfikując odpowiednio renderer.

A oto jak SiteSearchRenderer renderujący powinien wyglądać dla powyższego składnika:

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

} 

Aby użyć go w widoku, my oczywiście trzeba zarejestrować go jako znak. Tworzenie /WEB-INF/my.taglib.xml plik:

<?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> 

pamiętać, że nie potrzebują <renderer> w faces-config.xml za to więcej. Adnotacja @FacesRenderer może po prostu wykonać swoje zadanie na prawdziwych niestandardowych komponentach.Usuń więc wpis <renderer> z faces-config.xml utworzony na podstawie poprzedniego pytania.

teraz powiedzieć JSF, że masz niestandardowy TagLib według poniższego param kontekstowego w web.xml:

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

Wreszcie można go używać w następujący sposób:

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

Można nawet określić dodatkowe atrybuty, które zastąpią ustawienia domyślne w komponencie:

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

W przypadku autouzupełniania IDE w atrybutach należy podać każdą z nich jako oddzielną <attribute> w deklaracji w dokumencie .

+0

Wow. Rządzisz! Dzięki! – Adam

+0

Nie ma za co. – BalusC

+0

@BalusC, Jak osiągnąć to samo dla mojego komponentu niestandardowego, który został utworzony przy użyciu kompozytu takiego jak podane https://stackoverflow.com/questions/44454804/composite-attributes-returns-null-in-jsf-custom-components –