Вопрос по primefaces, jsf-2, custom-component, jsf – Добавление пользовательских атрибутов в компонент автозаполнения Primefaces в JSF

6

Я спросил о прохождении через атрибуты вдругой вопрос и обнаружил, что я мог бы создать собственный рендер для<p:autocomplete> компонент, но проблема в том, что мой пользовательский рендерер будет использоваться для каждого p: autocomplete в моем проекте (для всего сайта). Поэтому я решил создать пользовательский компонент, который расширяетorg.primefaces.component.autocomplete.AutoComplete и добавляет необходимые атрибуты в текстовое поле.

Сначала я хотел добавить конструктор, но он, похоже, не работает, поскольку карта атрибутов на этом этапе пуста:

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

Моя другая мысль состояла в том, чтобы оставить этот пользовательский компонент пустым (пустой класс), а затем указать пользовательский рендер, который расширяетorg.primefaces.component.autocomplete.AutoCompleteRenderer и измените атрибуты там.

После того, как все сказано и сделано, мне просто нужен способ сохранить эти атрибуты отдельно от этого одного текстового поля, так что простое размещение пользовательского средства визуализации в p: autoComplete не будет работать (если, возможно, я не смогу использовать для этого атрибут renderType = р: автозаполнение?).

Смотрел сериал (Доктор Хаус прямо сейчас). Имей немного терпения :) BalusC
@BalusC есть идеи? Adam
Ха-ха. Не проблемы. Я думаю, что всякий раз, когда я вижу вопрос JSF, я просто автоматически предполагаю, что ваш ответ будет, даже не глядя. Кто-нибудь может сказать JSF ниндзя? Adam

Ваш Ответ

1   ответ
18

Если вам нужен определенный компонент, который использует другой рендерер, чем<p:autoComplete> тогда вы действительно не сможете создать собственный компонент с собственным семейством и типом компонента. Вы все еще можете просто расширить PrimeFacesAutoComplete (и его средство визуализации), чтобы сохранить некоторый шаблонный код.

В пользовательском компоненте вам необходимо предоставить методы получения этих атрибутов. Вы можете также указать сеттеры, так что вы всегда можете переопределить значения по умолчанию со стороны представления. Те получатели / установщики должны в свою очередь делегироватьStateHelper.

Есть только небольшая проблема сx-webkit-* атрибутов.- является недопустимым символом в идентификаторах Java. Таким образом, вы должны переименовать геттеры / сеттеры и несколько изменить рендерер, так как стандартный рендерер полагается на то, что имя свойства компонента точно совпадает с именем атрибута тега.Update: Я это понимаюx-webkit-speech должен быть отображен как есть (так что нет необходимости в getter / setter) и что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 который вы создали на основе вашего предыдущего вопроса.

Теперь скажите 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" />

Для автозаполнения IDE для атрибутов вам нужно указать каждый из них как отдельный<attribute> в<tag> декларация вmy.taglib.xml.

Вот это да. Ты жжешь! Спасибо! Adam
Добро пожаловать.
@BalusC, как добиться этого же для моего пользовательского компонента, который создан с использованием compoiste, как указаноstackoverflow.com/questions/44454804/…

Похожие вопросы