Skip to content

Cordova - Contacts

The cordova-plugin-contacts plugin provides access to the device’s contact database. You can use it to find, create, and delete contacts. Note: This plugin requires user permission to access contacts.

Install the plugin using the Cordova CLI:

cordova plugin add cordova-plugin-contacts

After adding the plugin, rebuild your project for the platform(s) you are targeting (e.g., cordova build android).

In www/index.html, add buttons for contact operations and a div to display results:

<body>
<h1>Contacts Demo</h1>
<button id="createContactBtn">ADD CONTACT</button>
<button id="findContactBtn">FIND CONTACTS</button>
<button id="deleteContactBtn">DELETE 'Test User'</button>
<div id="contactResults"></div>
<script src="cordova.js"></script>
<script src="js/index.js"></script>
</body>

In www/js/index.js, within onDeviceReady, set up event listeners. All navigator.contacts API calls must be made after deviceready.

document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
console.log('Device is ready. Contacts API available.');
document.getElementById('createContactBtn').addEventListener('click', createContact);
document.getElementById('findContactBtn').addEventListener('click', findContacts);
document.getElementById('deleteContactBtn').addEventListener('click', deleteTestContact);
// It's good practice to check for permissions explicitly if needed,
// though the plugin often handles the initial prompt.
// For advanced scenarios, refer to permission plugins.
}
const displayResults = (message) => {
document.getElementById('contactResults').innerHTML = `<p>${message}</p>`;
console.log(message);
};
const displayError = (error) => {
let errorMessage = 'Operation failed.';
if (error && error.code) {
switch (error.code) {
case ContactError.UNKNOWN_ERROR: errorMessage = 'Unknown error.'; break;
case ContactError.INVALID_ARGUMENT_ERROR: errorMessage = 'Invalid argument.'; break;
case ContactError.TIMEOUT_ERROR: errorMessage = 'Timeout error.'; break;
case ContactError.PENDING_OPERATION_ERROR: errorMessage = 'Pending operation error.'; break;
case ContactError.IO_ERROR: errorMessage = 'I/O error.'; break;
case ContactError.NOT_SUPPORTED_ERROR: errorMessage = 'Not supported error.'; break;
case ContactError.PERMISSION_DENIED_ERROR: errorMessage = 'Permission denied.'; break;
default: errorMessage = `Error code: ${error.code}`;
}
}
document.getElementById('contactResults').innerHTML = `<p style="color: red;">Error: ${errorMessage}</p>`;
console.error('Contacts Error:', errorMessage, error);
};
// 3A - Create Contact
async function createContact() {
try {
const contact = navigator.contacts.create();
contact.displayName = "Test User";
contact.nickname = "Tester"; // Same as displayName by default
const name = new ContactName();
name.givenName = "Test";
name.familyName = "User";
contact.name = name;
const phoneNumbers = [];
phoneNumbers[0] = new ContactField('mobile', '123-456-7890', true); // preferred number
contact.phoneNumbers = phoneNumbers;
await new Promise((resolve, reject) => {
contact.save(() => resolve(), (err) => reject(err));
});
displayResults("Contact 'Test User' saved successfully!");
} catch (err) {
displayError(err);
}
}
// 3B - Find Contacts
async function findContacts() {
try {
const options = new ContactFindOptions();
options.filter = ""; // Empty filter to find all, or specify a search term e.g., "Test"
options.multiple = true;
// options.desiredFields = [navigator.contacts.fieldType.id, navigator.contacts.fieldType.displayName, navigator.contacts.fieldType.name]; // Specify fields if needed
const fields = ["displayName", "name", "phoneNumbers"]; // Fields to search within and retrieve
const contactsFound = await new Promise((resolve, reject) => {
navigator.contacts.find(fields, (contacts) => resolve(contacts), (err) => reject(err), options);
});
if (contactsFound.length === 0) {
displayResults("No contacts found.");
return;
}
let html = '<h3>Found Contacts:</h3><ul>';
contactsFound.forEach(contact => {
html += `<li>${contact.displayName || (contact.name ? contact.name.formatted : 'N/A')}`;
if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {
html += ` (${contact.phoneNumbers[0].value})`;
}
html += `</li>`;
});
html += '</ul>';
document.getElementById('contactResults').innerHTML = html;
console.log('Found contacts:', contactsFound);
} catch (err) {
displayError(err);
}
}
// 3C - Delete a Specific Contact
async function deleteTestContact() {
try {
const options = new ContactFindOptions();
options.filter = "Test User"; // Name of the contact to delete
options.multiple = false; // We expect to find one or rely on the first match
const fields = ["displayName"];
const contactsFound = await new Promise((resolve, reject) => {
navigator.contacts.find(fields, (contacts) => resolve(contacts), (err) => reject(err), options);
});
if (!contactsFound || contactsFound.length === 0) {
displayResults("Contact 'Test User' not found to delete.");
return;
}
const contactToDelete = contactsFound[0];
await new Promise((resolve, reject) => {
contactToDelete.remove(() => resolve(), (err) => reject(err));
});
displayResults(`Contact '${contactToDelete.displayName}' deleted successfully.`);
} catch (err) {
displayError(err);
}
}
  • Permissions: Accessing contacts is a sensitive operation. The plugin will typically trigger a permission request dialog from the OS. Your app should handle cases where permission is denied. The ContactError.PERMISSION_DENIED_ERROR code can indicate this. Consider using a dedicated permissions plugin for more granular control over permission requests and status checking.
  • Asynchronous Operations: All contact operations (save, find, remove) are asynchronous. The examples above use async/await with Promises for cleaner code. The original plugin API uses success and error callbacks.
  • Error Handling: Always provide error callback functions or use try/catch with Promises to handle potential issues, such as permission denial, I/O errors, or invalid arguments.
  • ContactFindOptions: Use filter to search for specific contacts. An empty string "" typically attempts to fetch all contacts (which can be slow if many contacts exist). multiple: true allows returning multiple matches.
  • Data Structure: Contacts can have complex data (multiple phone numbers, emails, addresses). Familiarize yourself with ContactName, ContactField, ContactAddress, etc. objects.
  • Platform Differences: While Cordova aims for cross-platform consistency, there might be subtle differences in how contacts are handled or what data is available on different operating systems.

Managing contacts is useful in:

  • Social networking apps for finding friends.
  • Communication apps for initiating calls or messages.
  • CRM or business apps for managing client information.
  • Apps that allow users to select contacts for sharing or other interactions.

For more details, consult the Cordova Contacts Plugin documentation.