7

別の質問でパススルー属性について尋ねたところ、コンポーネント用のカスタム レンダラーを作成できることがわかりました<p:autocomplete>が、問題は、私のプロジェクト (サイト全体) のすべての p:autocomplete にカスタム レンダラーが使用されることです。org.primefaces.component.autocomplete.AutoCompleteしたがって、必要な属性を拡張してテキスト ボックスに追加するカスタム コンポーネントを作成することにしました。

私の最初の考えは、コンストラクターを追加することでしたが、この時点で属性マップが null であるため、機能していないようです:

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

私の他の考えは、このカスタム コンポーネントを空 (空のクラス) のままにしてorg.primefaces.component.autocomplete.AutoCompleteRenderer、そこで属性を拡張および変更するカスタム レンダラーを指定することでした。

結局のところ、これらの属性をこの 1 つのテキスト ボックスに個別に保持する方法が必要なだけなので、p:autoComplete にカスタム レンダラーを配置するだけではうまくいきません (これに renderType= 属性を使用できる場合を除きます)。 p:autoComplete?)。

4

1 に答える 1

18

それとは異なるレンダラーを使用する特定のコンポーネントが必要な場合は<p:autoComplete>、独自のファミリとコンポーネントタイプを使用してカスタムコンポーネントを作成することはできません。PrimeFaces AutoComplete(およびそのレンダラー)を拡張するだけで、ボイラープレートコードを保存できます。

カスタムコンポーネントでは、これらの属性のゲッターを提供する必要があります。セッターを指定することもできます。これにより、ビュー側から常にデフォルト値をオーバーライドできます。それらのゲッター/セッターは、順番にに委任する必要がありStateHelperます。

属性には少しだけ問題がありx-webkit-*ます。これ-は、Java識別子の不正な文字です。したがって、標準のレンダラーはタグ属性名とまったく同じコンポーネントプロパティ名に依存しているため、ゲッター/セッターの名前を変更し、レンダラーを多少変更する必要があります。更新x-webkit-speech:それはそのままレンダリングする必要があることを理解しています(したがって、ゲッター/セッターは必要x-webkit-grammerありません)。これは実際にはタイプミスx-webkit-grammarです。

SiteSearchコンポーネントは次のようになります。

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

}

ゲッターにはすべてのデフォルト値が指定されていることに注意してください。eval()が返される場合はnull、代わりにデフォルト値が返されます。また、属性名をある程度無効にして、レンダラーを適宜変更するだけで、将来の非Webkitブラウザーで再利用できるようにしました。

上記のコンポーネントのSiteSearchRendererレンダラーは次のようになります。

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

}

ビューで使用するには、もちろんタグとして登録する必要があります。ファイルを作成し/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>

これにはもう<renderer>インは必要ないことに注意してください。faces-config.xmlアノテーションは、実際のカスタムコンポーネントでその@FacesRenderer役割を果たします。したがって、前の質問に基づいて作成した<renderer>エントリを削除します。faces-config.xml

次に、次のコンテキストパラメータでカスタムtaglibがあることをJSFに伝えますweb.xml

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

最後に、次のように使用できます。

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

コンポーネントに設定されているデフォルトを上書きする追加の属性を指定することもできます。

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

<attribute>属性のIDEオートコンプリートの場合、の<tag>宣言ですべてを個別に指定する必要がありますmy.taglib.xml

于 2012-05-13T03:13:26.113 に答える