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.