Добавление пользовательских атрибутов в компонент автозаполнения Primefaces в JSF
Я спросил об атрибутах pass through в другом вопросе и обнаружил, что могу создать собственный рендер для <p:autocomplete>
компонент, но проблема в том, что мой пользовательский рендерер будет использоваться для каждого p:autocomplete в моем проекте (для всего сайта). Поэтому я решил создать пользовательский компонент, который расширяет org.primefaces.component.autocomplete.AutoComplete
и добавляет необходимые атрибуты в текстовое поле.
Сначала я хотел добавить конструктор, но он, похоже, не работает, потому что карта атрибутов на этом этапе пуста:
@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
и измените атрибуты там.
После того, как все сказано и сделано, мне просто нужен способ сохранить эти атрибуты отдельно от этого одного текстового поля, так что простое размещение пользовательского средства визуализации в p:autoComplete не будет работать (если, возможно, я не смогу использовать для этого атрибут renderType =) р: автозаполнение?).
1 ответ
Если вам нужен определенный компонент, который использует другой рендерер, чем <p:autoComplete>
тогда вы действительно не сможете создать собственный компонент с собственным семейством и типом компонента. Вы все еще можете просто расширить PrimeFaces AutoComplete
(и его средство визуализации), чтобы сохранить некоторый шаблонный код.
В пользовательском компоненте вам необходимо предоставить методы получения этих атрибутов. Вы также можете указать сеттеры, так что вы всегда можете переопределить значения по умолчанию со стороны представления. Эти геттеры / сеттеры должны в свою очередь делегировать StateHelper
,
Есть только небольшая проблема с x-webkit-*
атрибутов. -
является недопустимым символом в идентификаторах Java. Таким образом, вы должны переименовать геттеры / сеттеры и несколько изменить рендерер, так как стандартный рендерер полагается на то, что имя свойства компонента точно совпадает с именем атрибута тега. Обновление: я понимаю, что 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, что у вас есть пользовательский taglib с помощью следующего контекстного параметра в 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
,