jsfbootsfaces

Implement autocomplete (typeahead with inputText) with BootsFaces


I develop a web application in Java EE, in this one there is an inputText allowing to search for a student according to his name. However, I am faced with a problem that I cannot find the solution to. I use an inputText with a typeahead (Bootsfaces), if I send it a List Etudiant (My List Object) it works however when I send it a List String no suggestion appears:/ In my controller (Java), I return a List containing the name and surname of each student and I would like to be able to make appear the suggestion of this list.

There is my xHtml code :

<b:inputText style="width:200px" value="" placeholder="Rechercher étudiant" typeahead="true" typeahead-values="#{etudiantController.getEtudiants()}"/>

There is my Controller (etudiantController) code :

public List<String> getEtudiants() {
    etudiants = gestionEtudiant.selectAll();
    List<String> listeNomPrenom = new ArrayList<String>();

    for(Etudiant e : etudiants) {
        listeNomPrenom.add(e.getNom() + " " + e.getPrenom());
    }

    return listeNomPrenom;
   }

I hope not to disturb with my post, thanks in advance ;)


Solution

  • So there are several things to address here...

    First of all, you need a backing bean value in order for the component to have a proper reference value. Not setting value might work for the auto completion depending on how the component is implemented, but you won't have access to what the user actually entered later in your controller. With some components it might make the component function in an undesirable way. So you need to connect it to a bean property.

    Secondly, typeahead-values is expecting either a straight up string, or a bean property. Only in very special circumstances will you ever need to call the getter of a bean property - so you should reference the property.

    Thirdly, instead of returning a new list of students, try to take advantage of Java's built in toString() functionality in your typeahead-values. Then you don't have to create a completely new list, but instead can rely on Java doing the conversion for you.

    So a complete solution mimicing what you are trying to do and translated to English would look like this;

    <?xml version="1.0" encoding="UTF-8"?>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" 
          xmlns:b="http://bootsfaces.net/ui">
        <h:head>
            <title>Autocomplete test</title>
        </h:head>
        <h:body>
            <h:form>
                <b:inputText value="#{studentBean.studentEntry}" placeholder="Search student"
                             typeahead="true" typeahead-values="#{studentBean.students}"/>
            </h:form>
        </h:body>
    </html>
    
    @Data
    @Named
    @ViewScoped
    public class StudentBean implements Serializable {
        private List<Student> students;
        private String studentEntry;
    
        @PostConstruct
        public void init() {
            students = new ArrayList<>();
            students.add(new Student("Carl", "Sagan"));
            students.add(new Student("Enrico", "Fermi"));
            students.add(new Student("Jay", "Miner"));
        }
    
        @Data
        @AllArgsConstructor
        public class Student {
            private String firstName;
            private String lastName;
    
            @Override
            public String toString() {
                return String.format("%s %s", lastName, firstName);
            }
        }
    }
    

    Note that this example uses Lombok - so the @Data annotation creates the needed setters and getters for the properties.

    Also notice how toString() actually flips the name and puts the surname first just like you do in your code.