Skip to content

Instantly share code, notes, and snippets.

@jakearchibald
Last active September 7, 2023 07:41
Show Gist options
  • Save jakearchibald/5774636 to your computer and use it in GitHub Desktop.
Save jakearchibald/5774636 to your computer and use it in GitHub Desktop.
/**
* Get requestAutocomplete data. Can only be called as part of an interaction event
* listener such as mouse up/down, click, key & touch.
*
* @param {{billing: boolean, shipping: boolean}} opts
* If billing is true, credit card & billing address details will be requested.
* If shipping is true, a shipping name & address will be requested.
* @param {function(response:Object<string, string>)} callback [description]
* You callback is passed a single response object in this format:
* {
* // May be an empty string (no error), or:
* // unsupported - Browser doesn't support requestAutocomplete
* // disabled - Browser supports requestAutocomplete but it's disabled or can't be called at this time
* // cancel - The user aborted the process
* // invalid - Some data may be incorrect/missing
* 'err': String,
* // The retrieved data, may be missing data on err
* 'data': {
* // Card data (if billing data requested)
* 'cc': {
* 'name': String,
* 'number': String,
* 'exp-month': String,
* 'exp-year': String,
* 'csc': String
* }
* // Billing address data (if billing data requested)
* 'billing': {
* 'email': String,
* 'name': String,
* 'tel': String,
* 'address-line1': String,
* 'address-line2': String,
* 'locality': String,
* 'region': String,
* 'postal-code': String,
* 'country': String
* }
* // Shipping data (if requested)
* 'shipping': {
* // same fields as billing
* }
* }
* }
* @return {void}
* @example
* requestUserData({
* billing: true,
* shipping: true
* }, function(response) {
* if (response.err == 'cancel') {
* // exit silently
* return;
* }
* if (response.err) {
* // fall back to normal form
* window.location.href = '/normal-checkout-form/';
* return;
* }
*
* // send response.data to your server,
* // be sure to validate on the server too!
* console.log(response.data);
* });
*/
function requestUserData(opts, callback) {
var getBilling = opts.billing;
var getShipping = opts.shipping;
var form = document.createElement('form');
var dataToRequest = [];
var inputs;
var addressData = [
'email',
'name',
'tel',
'address-line1',
'address-line2',
'locality',
'region',
'postal-code',
'country'
];
if (!form.requestAutocomplete) {
callback({
err: 'unsupported',
data: {}
});
return;
}
if (getBilling) {
dataToRequest.push(
'cc-name',
'cc-number',
'cc-exp-month',
'cc-exp-year',
'cc-csc'
);
dataToRequest = dataToRequest.concat(addressData.map(function(item) {
return 'billing ' + item;
}));
}
if (getShipping) {
dataToRequest = dataToRequest.concat(addressData.map(function(item) {
return 'shipping ' + item;
}));
}
inputs = dataToRequest.map(function(autocompleteVal) {
var input = document.createElement('input');
input.autocomplete = autocompleteVal;
form.appendChild(input);
return input;
});
function getData() {
var data = {};
if (getBilling) {
data.cc = {};
data.billing = {};
}
if (getShipping) {
data.shipping = {};
}
inputs.forEach(function(input) {
var type = input.autocomplete;
if (type.slice(0,2) == 'cc') {
data.cc[type.slice(3)] = input.value;
}
else if (type.slice(0,7) == 'billing') {
data.billing[type.slice(8)] = input.value;
}
else if (type.slice(0,8) == 'shipping') {
data.shipping[type.slice(9)] = input.value;
}
});
return data;
}
form.addEventListener('autocomplete', function() {
callback({
data: getData()
});
});
form.addEventListener('autocompleteerror', function(event) {
callback({
err: event.reason,
data: getData()
});
});
form.requestAutocomplete();
}
@danbeam
Copy link

danbeam commented Aug 27, 2013

document.body.appendChild(form);

is not necessary (and if you don't append it to the doc, you don't have to hide it, you can remove clean, etc.)

@jakearchibald
Copy link
Author

@danbeam Good point, fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment