ContactsManager
object, available as the contacts
property on the navigator
object. As it is only supported on Chrome on Android for now, the first thing we should concern ourselves with is checking for support. We can do so with this line:const supportsContacts = ('contacts' in navigator && 'ContactsManager' in window);
navigator.contacts.select
function. It takes two arguments, an array of properties you want to retrieve about the contacts and an object of options. The properties available are "name", "email", and "tel". (though there is an origin trial available for two extra properties; "address" and "icon"). There is one available option for the second argument—"multiple"—which can be true or false depending on whether you want to be able to return one or multiple contacts.select
will show the user a modal with an interface that allows them to select contacts and then returns a promise. The promise resolves with an array of contacts (even if you only asked for one). Each contact will have an array property for each of the properties you requested (as contacts applications allow for more than one phone number or email address). For example:navigator.contacts.select(["name", "tel"]) .then(contacts => { console.log(contacts); }) .catch(console.error); //=> [{ "name": ["Phil Nash"], "tel": ["+61412345678", "+447123456789"]}]
try { const contacts = await navigator.select(["name", "tel"]); console.log(contacts); } catch(error) { console.error(error); } //=> [{ "name": ["Phil Nash"], "tel": ["+61412345678", "+447123456789"]}]
git clone https://github.com/philnash/contact-picker-twilio-client.git -b getting-started cd contact-picker-twilio-client
npm install
.env.example
file to .env
:cp .env.example .env
.env
file with your account credentials. You can find your Twilio Account SID in your Twilio console. You also need to generate an API key and collect both the SID and the secret (check out this video if you want to know more about API keys and secrets). For the caller ID, you can either buy a new phone number or verify your own phone number. The final thing you need is a TwiML App.ngrok http 3000
https://YOUR_NGROK_SUBDOMAIN.ngrok.io/voice
.npm start
client/app.js
. This is all the code, aside from the Twilio Client JS library, that it takes to run this application.init
function let's do our check to see if the API is supported. If it is we have more code to write, but if it's not let's show an explanatory message.}); }); if ("contacts" in navigator && "ContactsManager" in window) { } else { const notSupported = document.createElement("p"); notSupported.classList.add("error"); notSupported.innerText = "Sorry, the contact picker API is not supported in your browser."; dialBtn.insertAdjacentElement("afterend", notSupported); } }; window.addEventListener("DOMContentLoaded", init);
<main>
element on the page, create a button and append it to the element.if ("contacts" in navigator && "ContactsManager" in window) { const mainElt = document.getElementsByTagName("main")[0]; const contactsButton = document.createElement("button"); contactsButton.innerText = "Choose contact"; mainElt.appendChild(contactsButton); }
async
function. Add the event handler before the code to append the button to the page.contactsButton.innerText = "Choose contact"; contactsButton.addEventListener("click", async () => { const contactProperties = ["name", "tel"]; const options = { multiple: false }; const contacts = await navigator.contacts.select(contactProperties, options); }); mainElt.appendChild(contactsButton); }
contacts
variable will be an array. If the user selected one contact it will have one item, if you passed the options { multiple: true }
then it may have more than one item, but if the user didn't select a contact at all then it will be an empty array. Before we move on we should check that there is a contact in the array.const contacts = await navigator.contacts.select(contactProperties, options); if (contacts.length > 0) { const contact = contacts[0]; const contactNumber = contact.tel.filter(tel => tel.length > 0)[0]; const contactName = contact.name.filter(name => name.length > 0)[0]; if (contactNumber) { phoneNumInput.value = contactNumber.replace(/\s/g, ""); dialBtn.innerText = `Dial ${contactName}`; } } }); }