Tuesday, January 3, 2012

On the Tenth Day of PhoneGapping: Searching Contacts

As I've mentioned before some of the W3C specifications that we base the PhoneGap API on are the difficult to understand. The Contacts API is definetly one of the hard to understand ones. Here is an example of searching the phones contacts and handling the gotchas that may arrise.

First here is the method signature used when searching contacts:


navigator.contacts.find(
    contactFields, 
    contactSuccess, 
    contactError, 
    contactFindOptions);
contactFields [Required]: is an array of strings that represent the fields from the Contact object you want returned as part of the search results. For example if you wanted to get the contacts display name and email addresses you would specify:
["displayName", "emails"]
if you would like to get each an every field populated in the returned array of Contacts you would specify, what I call, the fire hose option.
["*"]
However, be careful not to specify too many un-needed properties in the contactFields array. The array does double duty in the find command as the filter you specify in contactFindOptions is applied against each and every field in the contactFields array but we'll talk about that more later.

contactSuccess [Required]: is the success callback which is invoked with an array of contacts.

contactError [Optional]: an optional error callback which is invoked if something goes wrong with the find command. The only parameter to the function is a ContactError object.

contactFindOptions [Optional]: is an optional ContactFindOptions object which controls a couple of options in the find command. The two parameters in the contactFindOptions are

filter: specify what you want to match against.
multiple: set to true if you want more than one contact returned in the success callback.

by default filter is set to the wildcard (match everything) and multiple is set to true.

Find Examples

1) Find all the names and email addresses of contacts with Ottawa area phone numbers.
navigator.contacts.find(
    ["displayName", "name", "emails", "phoneNumbers"], 
    contactSuccess, 
    contactError, 
    {filter: "613", multiple: true});
2) Get all the contacts on the device.
navigator.contacts.find(
    ["*"], 
    contactSuccess, 
    contactError);
3) Find all contacts named "Bob" and where they work.
navigator.contacts.find(
    ["displayName", "name", "organizations"], 
    contactSuccess, 
    contactError, 
    {filter: "Bob", multiple: true});
Gotcha's

1) Slow search results.

As I mentioned earlier the more items you specify in contactFields the longer your search will take as the filter will have to be applied against it to see if the contact matches the filter. Please try and limit the contactFields array to only the parameters that you absolutely need.

2) Null values

Frequently people end up running into errors in their success callbacks as they don't guard against null values properly. According to the W3C spec if there are no results for array values like emails, phoneNumbers, addresses, etc. the code should return a null for theses values and not an empty array. So when folks try to loop through all the returned emails it will error out as you can't access the fields of a null value. So when you try to access one of these values guard agains the null.
if (contacts[i].phoneNumbers != null) {
    for (j=0; j < contacts[i].phonenumbers.length; j++) {
        // Do stuff
    }
}

No comments: