向 JSF 中的 Primefaces 自动完成组件添加自定义属性 [英] Adding Custom Attributes to Primefaces Autocomplete Component in JSF

查看:26
本文介绍了向 JSF 中的 Primefaces 自动完成组件添加自定义属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个不同的问题中询问了传递属性 并发现我可以为 <p:autocomplete> 组件创建一个自定义渲染器,但问题是我的自定义渲染器将用于我的项目(站点范围)中的每个 p:autocomplete.因此,我选择创建一个自定义组件,它扩展 org.primefaces.component.autocomplete.AutoComplete 并将必要的属性添加到文本框.

I asked about pass through attributes in a different question and found I could create a custom renderer for the <p:autocomplete> component but the problem is my custom renderer would be used for every p:autocomplete in my project (site-wide). Therefore I have elected to create a custom component which extends org.primefaces.component.autocomplete.AutoComplete and adds the necessary attributes to the text box.

我最初的想法是添加一个构造函数,但它似乎不起作用,因为此时属性映射为空:

My initial thought was to add a constructor but it doesn't seem to work because the attribute map is null at this point:

@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 并修改那里的属性.

My other thought was leave this custom component empty (empty class) and then specify a custom renderer that extends org.primefaces.component.autocomplete.AutoCompleteRenderer and modify the attributes there.

毕竟说了又做了,我只需要一种方法来将这些属性与这个文本框分开,因此仅在 p:autoComplete 上放置自定义渲染器是行不通的(除非我可以使用 renderType= 属性对于这个 p:autoComplete?).

After all is said and done, I just need a way to keep these attributes separate to this one text box so just putting a custom renderer on the p:autoComplete is not going to work (unless maybe I can use renderType= attribute for this one p:autoComplete?).

推荐答案

如果您需要使用与 <p:autoComplete> 不同的渲染器的特定组件,那么您真的无法解决创建具有自己的族和组件类型的自定义组件.您仍然可以扩展 PrimeFaces AutoComplete(及其渲染器)以保存一些样板代码.

If you need a specific component which uses a different renderer than <p:autoComplete> then you really can't go around creating a custom component with its own family and component type. You can still just extend the PrimeFaces AutoComplete (and its renderer) to save some boilerplate code.

在自定义组件中,您需要为这些属性提供 getter.您也可以指定 setter,这样您就可以始终覆盖视图端的默认值.这些 getter/setter 应该依次委托给 StateHelper.

In the custom component, you need to provide getters for those attributes. You could as good specify setters as well, this way you can always override the default values from in the view side. Those getters/setters should in turn delegate to StateHelper.

x-webkit-* 属性只有一个小问题.- 是 Java 标识符中的非法字符.因此,您必须重命名 getter/setter 并稍微更改渲染器,因为标准渲染器依赖于与标记属性名称完全相同的组件属性名称.更新:我知道 x-webkit-speech 应该按原样呈现(因此,不需要 getter/setter)并且 x-webkit-grammer 其实是打字错误,应该是x-webkit-grammar.

There's only a little problem with x-webkit-* attributes. The - is an illegal character in Java identifiers. So you have to rename the getters/setters and change the renderer somewhat as the standard renderer relies on the component property name being exactly the same as the tag attribute name. Update: I understand that x-webkit-speech should just be rendered as is (so, no getter/setter necessary) and that x-webkit-grammer is actually a typo, it should be 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);
    }

}

请注意,getter 已指定所有默认值.如果 eval() 返回 null,则将返回默认值.我还稍微中和了属性名称,以便它可以通过相应地修改渲染器来重用于任何未来的非 webkit 浏览器.

Please note that the getters have all default values specified. If the eval() returns null, then the default value will be returned instead. I have also neutralized the attribute names somewhat so that it can be reused for any future non-webkit browsers by just modifying the renderer accordingly.

对于上述组件,SiteSearchRenderer 渲染器应如下所示:

And here's how the SiteSearchRenderer renderer should look like for the above component:

@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 文件:

To use it in the view, we of course need to register it as a tag. Create a /WEB-INF/my.taglib.xml file:

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

请注意,您不再需要 faces-config.xml 中的 来实现此目的.@FacesRenderer 注释可以在真正的自定义组件上完成它的工作.所以删除 <renderer> 中的 faces-config.xml 条目,这是您根据之前的问题创建的.

Note that you don't need a <renderer> in faces-config.xml for this anymore. The @FacesRenderer annotation can just do its job on real custom components. So remove the <renderer> entry in faces-config.xml which you created based on your previous question.

现在通过 web.xml 中的以下上下文参数告诉 JSF 您有一个自定义 taglib:

Now tell JSF that you've got a custom taglib by the following context 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>

最后你可以使用它:

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

您甚至可以指定额外的属性来覆盖组件中设置的默认值:

You can even specify additional attributes which will override the defaults set in the component:

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

对于属性上的 IDE 自动完成,您需要在 中的 声明中将每个属性指定为单独的 my.taglib.xml.

For IDE autocomplete on attributes, you'd need to specify every one as a separate <attribute> in the <tag> declaration in the my.taglib.xml.

这篇关于向 JSF 中的 Primefaces 自动完成组件添加自定义属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆