Creating a typeahead/autocomplete/autosuggest input field

I need to assign people to jobs in projects. There are 3 tables involved: names of people, list of jobs, and the projects they will be on. What I want to be able to do is

  1. enter the first and last name of the person
  2. search for the person by name
  3. return the ID of that person
  4. select the job they will be doing and get that ID (I have the dropdown for that already)
  5. enter the jobID and personID into the project table.

I want to make sure that the name inputted is entered correctly. Can I use PHP to create an autosuggest input field for the names?

1 Like

Depending on how many names/ID’s you’re looking at, it may be simpler to prepopulate a javascript variable with the data and use it rather than trying to send the data back and forth while typing.

Is the list of persons particularly long?

1 Like

Yes, several hundreds.

1 Like

Ok, here is an example which fetches a JSON file containing 1000 employees. Maybe this is an option?

[
  {"id":1,"first_name":"Keven","last_name":"Insole"},
  {"id":2,"first_name":"Carolann","last_name":"D'Hooge"},
  {"id":3,"first_name":"Shepherd","last_name":"Di Maggio"},
  ...
]

It could obviously be fetched from an api instead.

As per some previous examples I have posted here on Sitepoint, I am using autocomplete.js

The setup as follows
HTML

<div class='container'>
    <form id='search-form' class='search-form' action=''>
        <h3 class='form-title'>Employees</h3>
        <input
            type='search'
            id='name'
            name='search_term'
            dir='ltr'
            spellcheck=false
            tabindex='1'
            aria-label='enter full name'
            placeholder='full name'
        >
        <!-- where autocomplete outputs a list to -->
        <datalist id='names'></datalist>
    </form>
    <output id='employee'></output>
</div>

Javascript

// generic function for fetching json data from a url
const fetchJson = async (url) => {
    try {
        const response = await fetch(url);
        return response.json();
    } catch (err) {
        console.error(err);
    }
}

async function main() {
    const employees = await fetchJson('https://assets.codepen.io/3351103/employees.json');
    // Using the employees JSON data: [{"id":1,"first_name":"Keven","last_name":"Insole"}, ...]
    // Create a new array of objects joining "first_name" and "last_name" to make a "fullName" property
    // include employee "id".
    const employeesSearchData = employees.map((employee) => {
        return {
            id: employee.id,
            fullName: `${employee['first_name']} ${employee['last_name']}`
        };
    });

    const autoCompleteJS = new autoComplete({
        selector: "#name",
        data: {
            src: employeesSearchData,
            keys: ['fullName'] // key to use for search
        },
        threshold: 2,
        resultsList: { maxResults: 10 },
        resultItem: { highlight: true },
        events: {
            input: {
                selection(event) {
                    // e.g. {id: 575, fullName: 'Rutherford Dobbie'}
                    const employee = event.detail.selection.value;
                    autoCompleteJS.input.value = employee.fullName;
                    // for illustration purposes
                    document.querySelector('#employee')
                        .textContent = `ID: ${employee.id}, Name: ${employee.fullName}`
                }
            },
        }
    });
    
    // Clear employee, when search is cleared.
    document.querySelector('#name').addEventListener('input', (event) => {
        if (!event.target.value) {
            document.querySelector('#employee').textContent = ""
        }
    })
}

main();

Information on using the fetch api

1 Like

In order to create a typeahead or autocomplete input field, you must dynamically filter and display suggestions based on the data entered by the user. It is recommended to use JavaScript libraries such as jQuery UI or frameworks such as React with controlled components. Make suggestions via APIs, update the dropdown list in real-time, and handle user selection efficiently for a seamless, user-friendly experience.

tho if the user’s already using PHP, and the employee data can be considered static (to the page load anyway), and it may be simpler to do something like…

<?php 
//Assume $db exists.
$employees = $db->query("SELECT id, CONCAT_WS(" ",first_name,lastname) AS fullName FROM employees")->fetchAll(PDO::FETCH_ASSOC);
?>
let employees = <?= json_encode($employees); ?>

which would eliminate the need for the fetching and the mapping.

(The user has mentioned “tables” and that they already have a dropdown for jobID in their OP, so i’m going to assume they’ve already got a database like object they’re interacting with.)

@m_hutley I just went to Mockaroo and from their basic example page deleted a few fields and hit the generate button to make some JSON. Just purely for an example.

If the mapping and joining in JS can be eliminated with SQL, then agreed that is probably a better way to go.

That said if you want the autocompletion, you would still need to fetch that json from the php, wouldn’t you?

edit: Just a thought, but what if you have three employees called ‘John Smith’?

1 Like

If you have the data written into the source by PHP during the page load, you wouldnt need to fetch it - it’s already there. You’d just need to compare the input field(s) to the values in the variable with a filter. shrug The user has already made a request to the page for it to load the form. The data isnt…excessively large, so at that point it’s mostly a question of saving overhead of multiple fetches vs initial load size, which… swings and roundabouts.

That’s a problem for the OP to elaborate on… the only differentiations we’re aware of are firstname, lastname, and ID. You could make the autocomplete show the ID along with the name results, but it would require the user to know which ID you’re trying to reference, which… rather defeats the purpose of a name lookup in the first place…

1 Like

Makes sense.

I missed your mix of PHP and JS in the let assignment. I was picturing the php file being a controller. Something you would sent a post request to and get json returned.