Create a form with custom autocomplete address field and CSV import values

I don’t have gravity forms but I experience in creating autocomplete fields using data from DB, csv, apis and so one.

The concept remains the same, it’s just how you call and receive the date that changes, depending in your source.

Starting with my csv, I looked for country names to stay as close to the address field meaning.
The csv structure is this

AD 42.546245 1.601554 Andorra
AE 23.424076 53.847818 United Arab Emirates
AF 33.93911 67.709953 Afghanistan

And so on…

Because I don’t have gravity form and I have no idea how it works, I made a simple example that will work with a input field, so no matter what you use it will work.
You will need to play around with css because you may not have the same containers as in my example.

Our form will consist of only one input field, out address, and a submit button.
The example focuses on the address field and its outcomplete feature.

<form class="gravity">
    <div class="input-wrap">
        <label>
            <span class="label">Address:</span>
            <div class="ajax-wrap">
                <input type="text" name="address">
            </div>
        </label>
    </div>
    <div class="input-wrap submit">
        <button type="submit">Send</button>
    </div>
</form>

Some basic css to give structure to everything

.gravity {
    padding: 15px; 
}

.gravity .input-wrap:not(:last-child) {
    margin-bottom: 15px;
}

.gravity .input-wrap .ajax-wrap {
    position: relative;
}

.gravity .input-wrap .ajax-wrap .address-ajax-results {
    position: absolute;
    top: 100%;
    left: 0;
    border: 1px solid #767676;
    background-color: #fff;
    width: 100%;
}

.gravity .input-wrap .ajax-wrap p.address-ajax-results {
    padding: 10px;
    font-weight: 700;
    margin: 0;
}

.gravity .input-wrap .ajax-wrap ul.address-ajax-results {
    max-height: 200px;
    overflow-x: hidden;
    overflow-y: auto;
}

.gravity .input-wrap .ajax-wrap ul.address-ajax-results li:not(:last-child) {
    border-bottom: 1px solid #767676;
}

.gravity .input-wrap .ajax-wrap ul.address-ajax-results li button {
    padding: 5px 10px;
    display: block;
    width: 100%;
    text-align: left;
}

.gravity .input-wrap .ajax-wrap ul.address-ajax-results li button:hover {
    background-color: #eee;
}

.gravity .input-wrap.submit button {
    display: block;
    background-color: #69AFE5;
    color: #fff;
    border-radius: 5px;
    padding: 5px 10px;
    width: 100%;
    font-weight: 700;
}

The client side logic for the request and output of our addresses

($ => {
    // timer for delaying ajax request for addresses
    let timerBeforeCheck;

    // how long to wait, in milliseconds, before the ajax request
    const timerDelay = 750;

    // minimum amount of charcters for a ajax request
    const minChar = 2;

    // our field target,
    // Change it to your needs
    const addressFieldTarget=".gravity [name="address"]";

    $(addressFieldTarget).on('keyup paste', e => {
        // clear previous timer
        clearTimeout(timerBeforeCheck);

        // the current element, address input
        const $this = $(e.currentTarget);

        // if minimum amount of charcters for a ajax request not met
        // remove previous results and stop
        if ($this.val().length < minChar) {
            // clear previous results
            $('.address-ajax-results').remove();
            return;
        }

        // start timer, after it finished (based on timerDelay)
        // send ajax request for the csv data
        timerBeforeCheck = setTimeout(() => {
            // clear previous results
            $('.address-ajax-results').remove();

            const userInput = $this.val();

            $.ajax({
                method: 'post',
                url: 'http://localhost/timber/wp-admin/admin-ajax.php',
                dataType: 'json',
                data: {
                    action: 'bt_get_form_addresses',
                    address: userInput
                },
                success: res => {
                    // if no results found display message
                    if (!res.length) $this.after('<p class="address-ajax-results">No results found.</p>');
                    else { // results found, build a results list a user can select from
                        let $list="";
                        $list += '<ul class="address-ajax-results">';

                        res.map(address => {
                            $list += '<li>';
                            $list +=   '<button type="button">' + address + '</button>';
                            $list += '</li>';
                        });

                        $list += '</ul>';

                        $this.after($list);
                    }
                }
            });
        }, timerDelay);
    });

    // show the addresses ajax response html input focus
    // if input already has value
    // that means that we already have the ajax response html
    $(addressFieldTarget).on('click', e => {
        // prevent out global document click close from triggering
        e.stopPropagation();
        if ($(e.currentTarget).val().length < minChar) return;
        $('.address-ajax-results').show();
    });

    // close the ajax results on any click on page
    $(document).on('click', () => {
        $('.address-ajax-results').hide();
    });

    // on addresses ajax response select
    // populate the address input
    $(document).on('click', '.address-ajax-results button', e => {
        // prevent out global document click close from triggering
        e.stopPropagation();

        // populate our input
        $(addressFieldTarget).val($(e.currentTarget).text());

        // close ajax results
        $('.address-ajax-results').hide();
    });
})(jQuery);

The server side logic that is responsible for retrieving the data from out csv file based on the user input.
My csv file is located in the root of the theme and named countries.csv, the php code is located in functions.php.
So to read the csv file we can do this fopen(__DIR__ . '/countries.csv', 'r').

// we use this two actions in order to make our ajax request
// available for both logged and not logged in users
add_action('wp_ajax_bt_get_form_addresses', 'bt_get_form_addresses');
add_action('wp_ajax_nopriv_bt_get_form_addresses', 'bt_get_form_addresses');
function bt_get_form_addresses () {
    // results to return
    $found = [];

    // try to open the csv
    if (($handle = fopen(__DIR__ . '/countries.csv', 'r')) !== FALSE) {
        // sanitize and check if the user value has anything
        if (!empty($address = filter_input(INPUT_POST, 'address', FILTER_SANITIZE_STRING))) {
            // start looping each csv row
            while (($data = fgetcsv($handle, 1000, ',')) !== FALSE) {
                // if our csv column value doesn't start with X
                // in this case the user value
                // continue to next csv row
                if (!preg_match('/^' . $address . '/i', $data[3])) continue;

                // add the found value to our results to return
                $found[] = $data[3];
            }
        }
    }

    // because or ajax request expects json format
    // we do the following
    echo json_encode($found);

    // this prevents any other code from executing
    die;
}

You can just copy/paste the code and it will work.
Just remember to create the csv file and follow the structure.
Here is an example on how it works on my local environment.

enter image description here