2012-05-13 29 views
5

Tôi đã hỏi về việc chuyển qua các thuộc tính trong một different question và thấy rằng tôi có thể tạo trình kết xuất tùy chỉnh cho thành phần <p:autocomplete> nhưng vấn đề là trình kết xuất tùy chỉnh của tôi sẽ được sử dụng cho mọi p: tự động hoàn thành trong dự án (toàn trang web). Vì vậy, tôi đã chọn tạo một thành phần tùy chỉnh mở rộng org.primefaces.component.autocomplete.AutoComplete và thêm các thuộc tính cần thiết vào hộp văn bản.Thêm thuộc tính tùy chỉnh vào thành phần tự động hoàn thành Primefaces trong JSF

suy nghĩ ban đầu của tôi là thêm một constructor nhưng nó dường như không làm việc vì bản đồ thuộc tính là null vào thời điểm này:

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

suy nghĩ khác của tôi là rời khỏi thành phần tùy chỉnh này rỗng (lớp trống) và sau đó chỉ định trình kết xuất tùy chỉnh mở rộng org.primefaces.component.autocomplete.AutoCompleteRenderer và sửa đổi các thuộc tính ở đó. Sau khi tất cả được nói và thực hiện, tôi chỉ cần một cách để giữ các thuộc tính này tách biệt với hộp văn bản này, do đó chỉ cần đặt một trình kết xuất tùy chỉnh trên p: autoComplete sẽ không hoạt động (trừ khi tôi có thể sử dụng renderType = =). thuộc tính cho p này: autoComplete?).

+0

@BalusC bất kỳ ý tưởng nào? – Adam

+0

Đã xem chuỗi video (House MD ngay bây giờ). Có một chút kiên nhẫn :) – BalusC

+0

Haha. Không vấn đề gì. Tôi nghĩ bất cứ khi nào tôi nhìn thấy một câu hỏi JSF tôi chỉ tự động giả định của bạn sẽ là câu trả lời mà không cần nhìn. Có ai nói JSF ninja không? – Adam

Trả lời

18

Nếu bạn cần một thành phần cụ thể sử dụng trình kết xuất khác hơn <p:autoComplete> thì bạn thực sự không thể tạo một thành phần tùy chỉnh với loại thành phần và gia đình riêng của nó. Bạn vẫn có thể mở rộng PrimeFaces AutoComplete (và trình kết xuất đồ họa) của nó để lưu một số mã soạn sẵn.

Trong thành phần tùy chỉnh, bạn cần cung cấp getters cho các thuộc tính đó. Bạn cũng có thể chỉ định các bộ định cư, bằng cách này bạn luôn có thể ghi đè các giá trị mặc định từ phía bên xem. Những getters/setters này sẽ lần lượt ủy quyền cho StateHelper.

Chỉ có một vấn đề nhỏ với thuộc tính x-webkit-*. - là ký tự không hợp lệ trong số nhận dạng Java. Vì vậy, bạn phải đổi tên getters/setters và thay đổi renderer phần nào như là renderer tiêu chuẩn dựa trên tên thuộc tính thành phần được chính xác giống như tên thuộc tính thẻ. Cập nhật: Tôi hiểu rằng x-webkit-speech chỉ nên được hiển thị như vậy (vì vậy, không cần thiết phải trả tiền/setter) và x-webkit-grammer thực sự là lỗi đánh máy, nó phải là x-webkit-grammar.

Đây là cách các thành phần SiteSearch thể trông giống như:

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

} 

Xin lưu ý rằng thu khí có tất cả các giá trị mặc định theo quy định. Nếu số eval() trả về null, thì giá trị mặc định sẽ được trả lại thay thế. Tôi cũng đã vô hiệu hóa các tên thuộc tính phần nào để nó có thể được tái sử dụng cho bất kỳ trình duyệt không phải webkit nào trong tương lai bằng cách chỉ sửa đổi trình kết xuất phù hợp.

Và dưới đây là cách các SiteSearchRenderer renderer sẽ giống như đối với các thành phần trên:

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

} 

Để sử dụng nó trong giao diện, chúng tôi tất nhiên cần phải đăng ký nó như là một thẻ. Tạo một file /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> 

Lưu ý rằng bạn không cần một <renderer> trong faces-config.xml cho điều này nữa. Chú thích @FacesRenderer chỉ có thể thực hiện công việc của mình trên các thành phần tùy chỉnh thực.Vì vậy, hãy xóa mục nhập <renderer> trong faces-config.xml mà bạn đã tạo dựa trên câu hỏi trước đó của mình.

Giờ thì nói cho JSF rằng bạn đã có một taglib tùy chỉnh bằng các param bối cảnh sau trong web.xml:

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

Cuối cùng bạn có thể sử dụng nó như sau:

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

Bạn thậm chí có thể chỉ định thêm các thuộc tính sẽ ghi đè các giá trị mặc định được đặt trong thành phần:

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

Để tự động hoàn thành IDE trên các thuộc tính, bạn cần phải chỉ định từng thuộc tính riêng lẻ <attribute> trong khai báo <tag> trong my.taglib.xml.

+0

Wow. Bạn đá! Cảm ơn! – Adam

+0

Bạn được chào đón. – BalusC

+0

@BalusC, Cách đạt được điều này tương tự cho thành phần tùy chỉnh của tôi, được tạo bằng cách sử dụng compoiste như https://stackoverflow.com/questions/44454804/composite-attributes-returns-null-in-jsf-custom-components –