Search code examples
javajsficefaces-1.8

Autocomplete unmatched results


I am trying to do autocomplete when I type in characters in ice:selectInputText Issue I am facing is when I type in characters it brings even names which is not matching with the characters I type. See the below screen shot for reference.

a

Ideally autocomplete should display only the first row from the result, however it displays rows which are not matching my typed characters.

Only Abell Maryland 20606 should display.

This is the code which is using for the comparison, how can I modify this to suit to my requirement which is to display only those results which is matching to what I type.

public int compare(Object o1, Object o2) {
        if (o1 instanceof SelectItem) {
            s1 = ((SelectItem) o1).getLabel();
        } else {
            s1 = o1.toString();
        }

        if (o2 instanceof SelectItem) {
            s2 = ((SelectItem) o2).getLabel();
        } else {
            s2 = o2.toString();
        }            
        return s1.compareToIgnoreCase(s2);
    }
};

I am following this tutorial from Icefaces

http://wiki.icefaces.org/display/ICE/Auto-Complete

Update

My code in autocomplete.jspx

 <ice:selectInputText rows="10" width="300"
                        listVar="emp"
                        valueChangeListener="#{mybean.updateList}"
                        listValue="#{mybean.list}">
                         <f:facet name="selectInputText">
                   <ice:panelGrid columns="3" columnClasses="empNameCol">
                         <ice:outputText value="#{emp.empName}"/>                         
                   </ice:panelGrid>

method updateList

public void updateList(ValueChangeEvent event) {

    setMatches(event);

    if (event.getComponent() instanceof SelectInputText) {
        SelectInputText autoComplete = (SelectInputText)event.getComponent();
        if (autoComplete.getSelectedItem() != null) {
            bean = (Bean)autoComplete.getSelectedItem().getValue();
        }            
        else {
            Bean tempCity = getMatch(autoComplete.getValue().toString());
            if (tempCity != null) {
                bean = tempCity;
            }
        }
    }
}

Method setMatches

private void setMatches(ValueChangeEvent event) {

Object searchWord = event.getNewValue();
int maxMatches = ((SelectInputText)event.getComponent()).getRows();
List matchList = new ArrayList(maxMatches);

try {
    int insert = 
        Collections.binarySearch(dictionary, searchWord, AutoCompleteDictionary.LABEL_COMPARATOR);            
    if (insert < 0) {
        insert = Math.abs(insert) - 1;
    }

    for (int i = 0; i < maxMatches; i++) {                                
        if ((insert + i) >= dictionary.size() || i >= maxMatches) {
            break;
        }
        matchList.add(dictionary.get(insert + i));
    }
} catch (Throwable e) {
    e.printStackTrace();
    logger.error("Erorr finding autocomplete matches" + e.getMessage());
}        
if (this.matchesList != null) {
    this.matchesList.clear();
    this.matchesList = null;
}
this.matchesList = matchList;

}

Update 2

Modified setMatches method

 private void setMatches(ValueChangeEvent event) {
        Object searchWord = event.getNewValue();
        int maxMatches = ((SelectInputText) event.getComponent()).getRows();
        List matchList = new ArrayList(maxMatches);
         try {
             for(int i = 0; i < dictionary.size(); i++) {
                 SelectItem s = (SelectItem)dictionary.get(i);
                 if(s.getLabel().startsWith(searchWord.toString())) {
                     matchList.add(s);
                     if(matchList.size() == maxMatches)
                         break;
                 }   
             }
         } catch (Throwable e) {
             e.printStackTrace();
             logger.error("Erorr finding autocomplete matches" + e.getMessage());
         }        
         if (this.matchesList != null) {
             this.matchesList.clear();
             this.matchesList = null;
         }
         this.matchesList = matchList;
         }

Solution

  • You have to update the list of SelectItems. Instead of just odering the list you have to filter the list (or creating a new one which only contains the matches). The next time the autocomplete-list renders it will evaluate the bound list again.

    The tutorial of icefaces has some sources attached (bottom). Take a look at AutoCompleteBean . The method updateList(ValueChangeEvent e) calls setMatches(e). Within this method the list is assigned with a new one.

    // assign new matchList
    if (this.matchesList != null) {
       this.matchesList.clear();
       this.matchesList = null;
    }
    this.matchesList = matchList;
    

    This causes the ui component to show only items which match the input.

    To sum it up: ice:selectInputList will always show the items contained in its list, so reduce the items in the list to show the relevant ones only.

    Regards

    Update

    private void setMatches(ValueChangeEvent event) {
    Object searchWord = event.getNewValue();
    int maxMatches = ((SelectInputText)event.getComponent()).getRows();
    List matchList = new ArrayList(maxMatches);
    
    try {
        for(int i = 0; i < dictionary.size(); i++) {
            SelectItem s = dictionary.get(i);
            if(s.getLabel().startsWith(searchWord)) {
                matchList.add(s);
                if(matchList.size() == maxMatches)
                    break;
            }   
        }
    } catch (Throwable e) {
        e.printStackTrace();
        logger.error("Erorr finding autocomplete matches" + e.getMessage());
    }        
    if (this.matchesList != null) {
        this.matchesList.clear();
        this.matchesList = null;
    }
    this.matchesList = matchList;
    }
    
    // note: not optimized, just to explain how to do.
    

    Update 2 (short version)

    /**
     * Fills the suggestionList with the given luceneResult.
     *
     * @param suggestionList                 The list to fill.
     * @param luceneResult                   The previously computed luceneResult.
     */
    private static void fillLookupSuggestionList(final List<SelectItem> suggestionList,
        LuceneResult luceneResult)
    {
        suggestionList.clear();
    
        String searchQuery = luceneResult.getLuceneResultConfig().getSearchQuery(); 
        if (luceneResult.getResultSize() <= 0)
        {
            suggestionList.add(new SelectItem(null, BundleHelper.i18n(LuceneLookupController.BUNDLE,
                LuceneLookupController.NO_ITEM_FOUND)));
        }
        else
        {
            List<LuceneResultEntry> results = luceneResult.getResult();
            for (LuceneResultEntry entry : results)
            {
                suggestionList.add(new SelectItem(entry.getMetaInfo(),
                    entry.getInfo().getDescription()));
            }
        }
    }