清單6顯示了監聽程序的最終實現:
清單6.監聽程序
- package com.coreJSf;
- import Java.io.Serializable;
- import Java.util.ArrayList;
- import Java.util.List;
- import Java.util.Map;
- import Javax.enterprise.context.SessionScoped;
- import Javax.faces.component.UIInput;
- import Javax.faces.component.UISelectItems;
- import Javax.faces.component.UISelectOne;
- import Javax.faces.context.FacesContext;
- import Javax.faces.event.ValueChangeEvent;
- import Javax.inject.Named;
- @Named
- @SessionScoped
- public class AutocompleteListener implements Serializable {
- private static String COMPLETION_ITEMS_ATTR = "coreJSf.completionItems";
- public void valueChanged(ValueChangeEvent e) {
- UIInput input = (UIInput)e.getSource();
- UISelectOne listbox = (UISelectOne)input.findComponent("listbox");
- if (listbox != null) {
- UISelectItems items = (UISelectItems)listbox.getChildren().get(0);
- Map<String, Object> attrs = listbox.getAttributes();
- List<String> newItems = getNewItems((String)input.getValue(),
- getCompletionItems(listbox, items, attrs));
- items.setValue(newItems.toArray());
- setListboxStyle(newItems.size(), attrs);
- }
- }
- public void completionItemSelected(ValueChangeEvent e) {
- UISelectOne listbox = (UISelectOne)e.getSource();
- UIInput input = (UIInput)listbox.findComponent("input");
- if(input != null) {
- input.setValue(listbox.getValue());
- }
- Map<String, Object> attrs = listbox.getAttributes();
- attrs.put("style", "display: none");
- }
- private List<String> getNewItems(String inputValue, String[] completionItems) {
- List<String> newnewItems = new ArrayList<String>();
- for (String item : completionItems) {
- String s = item.substring(0, inputValue.length());
- if (s.equalsIgnoreCase(inputValue))
- newItems.add(item);
- }
- return newItems;
- }
- private void setListboxStyle(int rows, Map<String, Object> attrs) {
- if (rows > 0) {
- Map<String, String> reqParams = FacesContext.getCurrentInstance()
- .getExternalContext().getRequestParameterMap();
- attrs.put("style", "display: inline; position: absolute; left: "
- + reqParams.get("x") + "px;" + " top: " + reqParams.get("y") + "px");
- attrs.put("size", rows == 1 ? 2 : rows);
- }
- else
- attrs.put("style", "display: none;");
- }
- private String[] getCompletionItems(UISelectOne listbox,
- UISelectItems items, Map<String, Object> attrs) {
- Strings] completionItems = (String[])attrs.get(COMPLETION_ITEMS_ATTR);
- if (completionItems == null) {
- completionItems = (String[])items.getValue();
- attrs.put(COMPLETION_ITEMS_ATTR, completionItems);
- }
- return completionItems;
- }
- }
JSF在Ajax調用期間調用監聽程序的valueChanged()方法來響應文本輸入中的keyup事件。該方法會創建一組新的完成項目,然後將列表框的項目設置為這個新的項目集。該方法還會設置列表框的樣式屬性,以確定AJax調用返回時是否顯示列表框。
清單6中的setListboxStyle()方法將使用x和y請求我在發起清單5中的AJax調用時指定的參數值。
JSF會在AJax調用期間調用監聽程序的其他公共方法completionItemSelected(),以響應列表框中的選擇事件。該方法會將列表框的值復制到文本輸入中,並隱藏列表框。
請注意,valueChanged()方法還會將原始完成項目存儲在列表框的某個屬性中。由於每個autoComplete組件都維護自己的完成項目列表,因此多個autoComplete組件可以在相同頁面中和諧共存,而不會影響彼此的完成項目。