PhoneGap* Exemplo da API Contacts API: Trabalhando com a base de dados de Contatos do dispositivo

Este artigo descreve o design e implementação de uma aplicação de exemplo da API Contacts do PhoneGap. Esta aplicação demonstra a  utilização da API de Contatos do PhoneGap para ter acesso à base de dados de contatos do dispositivo.

A aplicação suporta as seguintes ações: mostrar uma lista completa de contatos, mostrar todas as informações sobre um único contato, criar um novo contato, editar um contato existente, gravar um contato na base de dados de contatos do dispositivo, buscar por todos os contatos que atendam a um criério de busca, filtrar a lista de contatos por nome, ordenar a lista de contatos, remover um contato único e clonar um contato.

Esta aplicação utiliza as seguintes bibliotecas: jQuery, jQuery Mobile (para os estilos).

O código fonte pode ser encontrado aqui.

Aparência Final

A aplicação é composta por 4 páginas:

  1. Página de lista de contatos. Esta é a página principal da aplicação. Nesta página os seguintes itens são apresentados:
    1. Uma lista de contatos. Clicando um dos contatos, a página com informações do contato é acessada.
    2. Botão Opções. Ele abre um menu pop-up, de onde o usuário pode acessar a página de Busca Avançada, a página de Editar Contato ou alterar as preferências de apresentação ou a ordenação da lista de contatos.
    3. A entrada de Busca. A lista de contatos é filtrada de forma que somente os contatos com um dado nome ou sobrenome ou iniciando com uma determinada letra sejam apresentados.
    4. O link para informações sobre a licença da aplicação de exemplo.
  2. Página de informações do contato. Ela apresenta todas as informações existentes de um determinado contato (ex. nome completo, foto, lista de números de telefone, endereços de e-mail, etc.). O botão opções provê o acesso às seguintes funcionalidades:
    1. Criar um contato duplicado: uma cópia exata do contato selecionado é criada na base de dados de contatos do dispositivo.
    2. Editar um contato: abre a página de Editar Contato, já preenchida com as informações do contato atual.
    3. Remover um contato: remove de forma permanente um contato da base de dados de contato do dispositivo.
  3. Página Editar Contato: provê um formulário onde as informações de contato podem ser coletadas e armazenadas. Os campos do formulário são gerados e adicionados dinamicamente (o diálogo do selecionador de tipo de contato é aberto para se escolher o tipo de campo necessário).
  4. Página de Busca Avançada, onde o tipo de campo de contato onde a busca será realizada é escolhido e a string de busca é digitada. Depois que a busca for completada, a lista de contatos é atualizada para conter apenas os contatos que satisfizerem o critério.
Abaixo estão uma captura das páginas da Lista de Contatos e das Informações de Contato.

Considerações no Design e na Estrutura Geral.

A aplicação é iniciada com a página da Lista de Contatos. Quando um item da lista de contatos for selecionado, o trabalho com apenas um contato é iniciado. Para isto, uma variável global activeContact da classe Contact é inicializada (activeContact contém todas as informações de contato recebidas da base de dados de contatos) e é usada adiante para provêr interações entre as páginas de Informações de Contato e a Editar de Contato e a base de dados de contato do dispositivo, no casos onde o armazenamento de alterações nas informações de contatos sejam necessários. Quando a página com a Lista de Contatos volta á ativa, o contato ativo é removido, tendo em vista que o trabalho com um único contato é então finalizado.

As informações de contato são consultadas usando a API Contacts do PhoneGap.

O objeto DisplayableContactList

O conteúdo da Lista de Contatos é gerenciado pelo objeto DisplayableContactList. O objeto DisplayableContactList possui as seguintes funções: ele interage com a base de dados de contatos, consulta a base para receber informações parciais de cada contato, constrói o contaúdo html da lista de contatos, gerencia a lista de contatos (ordena a apresentação do conteúdo, aplica as preferências do usuário, etc). O objeto HTML construído por esta classe consiste dos itens da lista de contatos que podem ser clicados e servem para abrir a página de informações de contato. Abaixo está uma declaração schematica da classe com seus métodos públicos:

// Lista das representações reduzidas dos contatos, que são apresentadas na lista de contatos

function DisplayableContactList(contListContainer) {

    ....

    var sortPref = SortPref.ASC;

    var dispPref = DispPref.NAME_FIRST;

    // Consulta a base de dados de contatos do dispositivo e redesenha a lista de contatos

    this.updateList = function(filter, filterField, additionalFieldsArray) { ... }

    // Adiciona a lista de contatos na página. Contatos que não satisfaçam a string de filtro ficam invisíveis.

    // Se o filtro estiver vazio, todos os contatos são apresentados.

    this.drawContactList = function(filter) { ... }

    // Ajusta as novas preferências de ordenação de contatos e redesenha a lista de contatos

    this.setSortPref = function(newPref, filter) { ... }

    // Ajusta as novas preferências de apresentação de contatos e  redesenha a lista de contatos

    this.setDispPref = function(newPref, filter) { ... }

    ...

O objeto armazena dois parâmetros: preferências de ordenação e apresentação, selecionadas pelo usuário.

O método updateList() consulta a base de dados de contatos para receber a lista de contatos armazenada na base de dados do dispositivo. A consulta é formada para receber os campos ("id", "name", "photos"), mas o vetor de campos adicionais pode ser fornecido para buscar contatos com retorno and/or. A lista de contatos somente é filtrada se o filtro e os campos do filtro forem fornecidos. O proceso de filtragem é feito pelo método checkFilter() (ele compara a string de filtro e o valor no campo de filtro do contato para uma correspondência parcial). Como resultado, o método updateList() forma, ordena e desenha a lista de contatos.

Problemas:

A consulta à base de dados de contatos é implementada de acordo com as especificações W3C, que requerem que os campos de retorno e os campos aos quais o filtro de busca é aplicado sejam os mesmos. Por exemplo, se nós quisermos retornar os campos "name" e "phoneNumbers", mas somente para um contato com um id específico, a consulta deveria ser algo como ["id", "name", "phoneNumbers"]. Como resultado, não apenas o contato com o id especificado será retornado, mas a lista dos contatos pode ser retornada, por exemplo, junto com os contatos que possuem um phoneNumber que seja parcialmente correspondente ao id requerido. Esta é a razão pela qual nestes casos a filtragem posterior é necessária.

Os métodos drawContactList(filter), setSortPref(newPref, filter) e setDispPref(newPref, filter) trabalham antecipadamente com a construção do conteúdo da página html para filtrar a lista de contatos de acordo com o critério de busca (inserido na entrada da busca na página principal), para alterar a ordem de ordenação dos contatos ou para fazer com que a lista apresente o sobrenome antes do nome (ou ao contrário). Por este motivo, a base de dados de contatos não é consultada.

Página de Informações de Contato

O conteúdo da página de Informações de Contato, completada com as informações requeridas de um contato, é gerada dinamicamente quando um contato na lista é clicado. Para isto, o método showInfo(contactID, searchCriteria) é chamado. O método gera o conteúdo html que contém as informações solicitadas e que precisam ser adicionadas à página. Adicionalmente, o activeContact é atribuído ao contato que foi consultado. Para obter as informações para a apresentação, o método Contacts.find() é chamado. Os dois parâmetros passados para esta função são o id do contato solicitado e o critério de busca, que é passado ao método Contacts.find() como um filtro. O critério de busca deve ser o mais descritível possível. Aqui, o sobrenome é utilizado se estiver presente, então o nome é usado se o sobrenome não estiver disponível, e finalmente o id do contato. Quando a lista de contatos é recebida, o contato com o id recebido é buscado.

index.html

        <!-- Página de Informações de Contato -->

        <div data-role="page" id="cont_info_page" data-theme="a">

            ....

            <div data-role="content">

                <div id="contact_info">

                    <!-- Content will be dynamically added -->

                </div>

            </div><!-- end: Content -->

        </div><!-- end: Contact Information page -->

contacts.js

// Forma a página "Contact information"

function showInfo(contactID, searchCriteria) {

    var contInfoContainer = getElement("contact_info");

    var contactFields = ["*"];

    var contactFindOptions = new ContactFindOptions();

    contactFindOptions.filter = searchCriteria;

    contactFindOptions.multiple = true;

    navigator.contacts.find(contactFields, contactSuccess, contactError, contactFindOptions);

    contInfoContainer.innerHTML = "";

    function contactSuccess(contacts) {

        contInfoContainer.innerHTML = "";

        for (var i = 0; i < contacts.length; i++) {

            if (contacts[i].id == contactID) {

                activeContact = contacts[i];

                var cNameSection = ...;                                // aqui, a string html da seção nome é formada á partir de contacts[i].name

                var cPhotoSection = ...;                                // aqui, a string html da seção foto é formada á partir de contacts[i].photos

                var cPhoneNumbersSection = ...;                  // aqui, a string html da seção números de telefone é formada á partir de contacts[i].phoneNumbers

                var cEmailsSection = "";                               // aqui, a string html da seção e-mail é formada á partir de contacts[i].emails

                // então os IMs, endereços de sites, e demais seções são formados à partir de seus campos

                contInfoContainer.innerHTML +=  cPhotoSection + cNameSection + cPhoneNumbersSection + cEmailsSection + 

                                                cIMsSection + cUrlsSection + cAddressesSection + cOrganizationsSection + 

                                                cNoteSection;

                $.mobile.changePage("#cont_info_page", { transition: "pop" });

                break;

            }

        }

    }

    function contactError(contactError) {

        contInfoContainer.innerHTML = "Contacts are unavailable";

        $.mobile.changePage("#cont_info_page", { transition: "pop" });

    }

}

Removendo um Contato

A operação "Remover contato" usa o método contact.remove(onSuccess, onError)  da classe Contact. Quando a remoção for feita com sucesso, a aplicação atualiza a lista de contatos e altera para a página de lista de contatos. O método é chamado através do menu Remove contact na página de Informações de Contato.contacts.js

function onDeviceReady() {

    ....

    $("#remove_ok_button").bind ("click", onRemoveContact); 

    ....

}

// Chamada pela remoção de um contato existente 

function onRemoveContact(e) {

    activeContact.remove(onSuccess, onError);

    function onSuccess() {

        alert("The contact was successfully removed");

        displContactList.updateList();

        $.mobile.changePage("#cont_list_page", { transition: "pop" }); 

    };

    function onError(contactError) {

        alert("Cannot remove contact: error " + contactError.code);

        $.mobile.changePage("#cont_info_page", { transition: "pop" }); 

    };

}

Clonando um Contato

Um contato é clonado usando a função contact.clone() da classe Contact. Ela retorna uma cópia do contato e esta cópia é salva com o método save(onSuccess, onError) na base de dados do dispositivo. O método é chamado através do menu "Create contact copy" na página de informações de contato.

contacts.js

// Chamado quando o Cordova foi completamente carregado (e portanto chamadas à funções do Cordova passam a ser seguras)

function onDeviceReady() {

   ....

   $("#clone_contact_button").bind ("click", onSaveContactCopy); 

   ....

}

// Chamada por uma solicitação de duplicação de contato existente

function onSaveContactCopy(e) {

    ...

    var newContact = activeContact.clone();

    newContact.name.familyName = newContact.name.familyName + " (copy)";

    newContact.save(onSuccess, onError);

    function onSuccess(contact) {

        alert("The contact duplicate " + contact.name.givenName + " " + contact.name.familyName + " was successfully created");

        displContactList.updateList();

    };

   function onError(contactError) {

        alert("The contact cannot be duplicated. Error: " + contactError.code);

    };

}

Editando um Contato e Criando um Novo Contato

A edição de um contato (novo contato ou contato existente) é realizada através do formuário de informações do contato, que é criado na página de edição de contatos. Se a opção de edição for selecionada, o formulário é preennchido com as propriedades do activeContact. Se a opção de criação de um novo contato for selecionada, um formulário em branco é criado. O formulário é criado e gerenciado pelo objeto Contact Form.

contacts.js

// Chamado quando o Cordova foi completamente carregado (e portanto chamadas à funções do Cordova passam a ser seguras)

function onDeviceReady() {

    .....

    $("#edit_contact_button").bind ("click", onEditContact);

    $("#new_contact_ok_nav").bind ("click", onSaveContact);

    .....

}

// Chamada para a criação de um novo contato

function onNewContact(e) {

    contactForm.buildContactForm(null);  

    $.mobile.changePage("#edit_contact_page", { transition: "pop" });

    .....

}

// Chamada para a edição de um contato existente

function onEditContact(e) {

    contactForm.buildContactForm(activeContact);  

    $.mobile.changePage("#edit_contact_page", { transition: "pop" });

}

O Objeto ContactForm 

O formulário de edição de contatos é gerado dinamicamente. Cada propriedade do contato corresponde a uma única seção no formulário. Se a propriedade possui uma natureza simples, a seção correspondente é feita visível ou invisível dependendo da presença da propriedade. Se a propriedade representa um vetor, o número requerido de subseções correspondentes a cada um dos elementos do vetor pode ser anexado à seção correspondente (se a seção não tiver nenhuma subseção, ela será invisível). Seções / subseções são anexadas através de um clique no botão "Add item" (o método contactForm.addItem() é chamado). A subseção pode ser removida pelo método remove(). Na caixa de diálogo de adição de um item, o tipo de item a ser selcionado (ex. número de telefone, email, etc) é fixado com o método fixChooser(). O método fixChooser() desabilita as opções de seleção correspondentes nas seções de formulário que não devem ter subseções adicionais.

Seções e subseções são definidas como strings pela simplicidade: são inicializadas no método defineSectionPatterns(). 

Para construir e inicializar o formulário de contatos, o método buildContactForm() é usado: ele constrói a sequência de seções do formulário e a adiciona à raiz do formulário, e então consulta a base de dados de contatos para preencher o formulário se o activeContact não for nulo.

Os métodos como getNames(), getNicknames(), getPhoneNumbers() e outras funções retornam conjuntos de informações digitadas pelo usuário para gravar na base de dados de contatos. Segue abaixo o esquema do código: 

index.html

<!-- Página de edição de contato -->

      <div data-role="page" id="edit_contact_page" data-theme="a">

            <div data-role="header">   .....   </div>

            <div data-role="content">

                    <form name="new_contact_form" id="new_contact_form">

                            <!-- O formlário é criado dinamicamente -->

                    </form>

            </div>

            <div data-role="footer" >   .....   </div>

</div><!-- fim: página de Edição de contato -->

contacts.form.js

// O objeto representando um formulário de edição de contato

function ContactForm() {

    var formSectionPatterns = defineSectionPatterns();

    // Adiciona uma seção de formulário correspondente ao itemName (ex. número de telefone, etc) do formulário.

    // O itemName deve corresponder a uma propriedade da classe Contact.

    this.addItem = function(itemName) { ... }

    ....

    // Cria o formulário de edição de contatos (e preenche o formulário se as informações de contato forem fornecidas)

    this.buildContactForm = function(contact) {

        var contactPropBatch = getElement("new_contact_form");

        .....

        contactPropBatch.innerHTML = formSectionPatterns.nameSec + formSectionPatterns.phonesSec + 

                                     formSectionPatterns.emailsSec + formSectionPatterns.addressesSec +

                                     formSectionPatterns.imsSec + formSectionPatterns.organizationsSec +

                                     formSectionPatterns.noteSec + formSectionPatterns.photoSec + 

                                     formSectionPatterns.urlsSec +

                                     "<a id='addNewItem_button' href='#item_chooser_page' data-rel='dialog' data-role='button' data-icon='plus' onclick='fixChooser();'>Add detail</a>";

        if (contact != null) {

            if (contact.name != null) {

                $("#given_name_input").val(contact.name.givenName);

                $("#family_input").val(contact.name.familyName);

                $("#middle_input").val(contact.name.middleName);

                $("#honorificPrefix_input").val(contact.name.honorificPrefix);

                $("#honorificSuffix_input").val(contact.name.honorificSuffix);

                $("#nickname_input").val(contact.nickname);

            }

            if (contact.phoneNumbers && (contact.phoneNumbers.length > 0)) {

                var phoneSec = getElement("phonesSec");

                buildSection(phoneSec, "phoneNumber", contact.phoneNumbers.length);

                for (var i = 0; i < contact.phoneNumbers.length; i++) {

                    getElement("phoneNumbersType_input_" + i).value = contact.phoneNumbers[i].type;

                    getElement("phoneNumbers_input_" + i).value = contact.phoneNumbers[i].value;

                }

            }

            .....                       // mais preenchimento de formulário

        }

        $("#new_contact_form").trigger("create");        // atualização do formulário (requerido pelo  jQuery Mobile)

    }

    // Adiciona o número de subseções (subsectionNumber) necessárias à seção especificada do formulário

    function buildSection(section, subsectionName, subsectionNumber) { ..... }

    // Retorna o objeto contendo todas as strings html formando as partes do formulári

    function defineSectionPatterns() { ..... }

    // Retorna o elemento DOM  (subseção de formulário) com os unique ids apropriados  

    function getFormSection(propertyName, i) { ..... }

    // Retorna as informações de nome de contato digitada pelo usuári

    this.getNames = function() { .... }

    // Retorna o apelido de contato 

    this.getNickname = function() { ..... }

    // Retorna os números de telefone digitados pelo usuário

    this.getPhoneNumbers = function() { ..... }

    // Retorna os emails de contato digitados pelo usuário

    this.getEmails = function() { ...... }

    // Retorna os IMs do contato digitados pelo usuário

    this.getIMs = function() { ..... }

    // Retorna as URLs de contato digitadas pelo usuário

    this.getURLs = function() { ...... }

    // Retorna as informações da foto do contato fornecidas pelo usuário

    this.getPhotos = function() { ..... }

    // Retorna o endereço do contato digitado pelo usuário

    this.getAddresses = function() { ..... }

    // Retorna a organização do contato digitada pelo usuário

    this.getOrganizations = function() { ..... }

    // Retorna as anotações do contato digitadas pelo usuário

    this.getNote = function() { ...... }

}

// Remove a subseção do formulário. Deve ser disparada pelo evento de clique no botão remover.

// O botão remover deve estar contido na subseção que será removida.

function remove(e) { ..... }

// Desabilita os itens do selecionador de "Add subsection" que sejam únicos e que já estejam presentes no formulário

function fixChooser() { ...... }

Gravando um contato

Para gravar um contato novo ou editado, o método onSaveContact(e) é chamado. Ele solicita os dados de contato do formulário de contato e grava-os no novo contato (se um novo contato for criado com o método navigator.contacts.create()) ou atualiza o activeContact (se for parte do processo de edição de contato, onde o contato ativo é o contato editado).

Nota:

No Android, se for atualizar um dos campos de contato, como número de telefone ou e-mail, é importante atualizar as propriedades de cada campo de contato existente ao invés de substituí-las com as novas instâncias. No último caso, os campos serão adicionados aos já existentes, ao invés de substituí-los. Isso ocorre porque cada phoneNumer, por exemplo, possui um id que é comparadado com a base de dados de contato do Android. Quando salvar um contato, se o id existir o campo é modificado. Se o id não existir, o campo é adicionado. É por isso, por exemplo, que a melhor forma de remover um número de telefone é atribuir a sua propriedade para "" (fonte: Q&As aqui).

// Chamada para gravar um contato alterado

function onSaveContact(e) {

    var toSave;

    if (activeContact) {

        toSave = activeContact;

    } else {

        toSave = navigator.contacts.create();

    }

    // gravando o nome:

    initName();

    // gravando o apelido:

    toSave.nickname = contactForm.getNickname();

    // gravando os telefones:

    initContactFieldVals("phoneNumbers", contactForm.getPhoneNumbers());

    ....                   // here follows the same procedure for emails, ims, urls, addresses, organizations saving

    // gravando anotações:

    var note = contactForm.getNote();

    if (!isEmptyOrBlank(note)) {

        toSave.note = note;

    }

    // gravando fotos:

    initContactFieldVals("photos", contactForm.getPhotos());

    toSave.save(onSuccess,onError);


    function onSuccess(contact) {

        alert("The contact was successfully saved");

        displContactList.updateList();

        $.mobile.changePage("#cont_list_page", { transition: "pop" });

    };


    function onError(contactError) {

        alert("The contact cannot be saved: error; " + contactError.code);

    };

    

    function initName() {

        ...                   // recebendo os dados de nome para gravar

    };

    

    function initContactFieldVals(contactFieldName, contactFieldValsArray) {

        if (!toSave[contactFieldName] && (contactFieldValsArray.length > 0)) {

            toSave[contactFieldName] = [];

        } 

        for (var i = 0; i < contactFieldValsArray.length; i++) {

            if (!toSave[contactFieldName][i]) {

                if (contactFieldName == "addresses") {

                    toSave[contactFieldName][i] = new ContactAddress();

                } else if (contactFieldName == "organizations") {

                    toSave[contactFieldName][i] = new ContactOrganization();

                } else {

                    toSave[contactFieldName][i] = new ContactField();

                }

            }

            for (var key in contactFieldValsArray[i]) {

                toSave[contactFieldName][i][key] = contactFieldValsArray[i][key];

            }

        }

        if (toSave[contactFieldName]) {

            for (var i = contactFieldValsArray.length; i < toSave[contactFieldName].length; i++) {

                if (toSave[contactFieldName][i]) {

                    for (var key in toSave[contactFieldName][i]) {

                        if (key.toLowerCase() != "id") {

                            toSave[contactFieldName][i][key] = "";

                        }

                    }

                }

            }

        }

    };

}

Obtendo Fotos do Dispositivo

Para obter fotos do dispositivo com o propósito de defini-las como o avatar de um contaro, a PhoneGap Camera API é utilizada. O método Camera.getPicture(onCaptureSuccess, onCaptureError, [ cameraOptions ]) obtem a foto dos álbuns de fotos armazenados no dispositivo e é chamado com parâmetros constantes (por favor, leia a documentação da API para uma explicação mais aprofundada). Se a imagem for escolhida com sucesso, ela é configurada como a fonte de imagem no formulário de Edição de Contato. Em caso contrário, nada é alterado:

// Seleciona uma foto do Álbum de Fotos

function selectPhoto(e) {

    navigator.camera.getPicture(onCaptureSuccess, 

                                onCaptureError, 

                                { quality : 50, 

                                  destinationType : Camera.DestinationType.FILE_URI, 

                                  sourceType : Camera.PictureSourceType.PHOTOLIBRARY, 

                                  allowEdit : false, 

                                  encodingType : Camera.EncodingType.JPEG,

                                  targetWidth : 100,

                                  targetHeight : 100,

                                  mediaType: Camera.MediaType.PICTURE,

                                  saveToPhotoAlbum : false,

                                  correctOrientation: true

                                });

    // Define a URL da foto do contato

    function onCaptureSuccess(imageData) {

        getElement("photo_loc_input").src = imageData;

    }

    function onCaptureError(message) { }

}

Nota:

Dispositivos Ripple e reais tratam urls de imagens de forma diferente. Atualmente remover uma imagem de contato funciona bem com Ripple, mas falha em um dispositivo real.

Busca Avançada

A busca avançada é iniciada pressionando o botão "searchby_chooser_ok_button" e é gerenciada pela página Advanced Search Chooser, que contém a seleção do campo de busca e da string de busca: 

        <!-- Advanced Search Chooser page -->

        <div data-role="page" id="searchby_chooser_page" data-theme="a">

            <div data-role="header" data-position="fixed">

                <h3>Advanced search</h3>

            </div>

            <div data-role="content">

                <div>

                    <label for="searchby_chooser_input">Choose a search criteria:</label>

                    <select id='searchby_chooser_input' name='searchby_chooser_input' data-mini='true'>

                        <option value='name'>Name</option>

                        <option value='nickname'>Nickname</option>

                        <option value='phoneNumbers' selected='selected'>Phone</option>

                        <option value='emails'>Email</option>

                        <option value='ims'>IM</option>

                        <option value='urls'>URL</option>

                        <option value='addresses'>Address</option>

                        <option value='organizations'>Organization</option>

                    </select>

                    <label for="search_val_input">Enter the value to search for:</label>

                    <input id="search_val_input" name="search_val_input" type="text" />

                    <div style="width: 100%; margin: 0 auto; margin-left: auto; margin-right: auto; align: center; text-align: center;">

                        <a href="#" id="searchby_chooser_ok_button" data-role="button" data-theme="b" data-inline="true">Go!</a>

                    </div>

                </div>

            </div><!-- end: Content -->

        </div><!-- end: Advanced Search Chooser page -->

Depois da seleção do campo de busca e da digitação da string de busca, a base de dados de contatos do dispositivo é consultada pelo método searchByCriteria(), que chama o objeto DisplayableContactList para formar a lista satisfazendo o critério de busca, com o campo adicional de busca (selecionado pelo usuário). Ele também adiciona o botão "Show full list" para retornar a lista completa de contatos.

function onLoad() {

    ....

    $("#searchby_chooser_ok_button").bind ("click", searchByCriteria); 

    ....

}

// Mostra a lista de contatos satisfazendo os critérios da busca avançada

function searchByCriteria() {

    $.mobile.changePage("#cont_list_page", { transition : "pop" });

    var searchCriteria = getElement("searchby_chooser_input").options[getElement("searchby_chooser_input").selectedIndex].value;

    var searchVal = getElement("search_val_input").value;

    getElement("search_val_input").value = "";

    var addF = [];

    addF.push(searchCriteria);

    displContactList.updateList(searchVal, searchCriteria, addF);

    var div = getElement("full_list_button_container");

    if (div) {

        div.innerHTML = '<a href="#" id="full_list_button" data-role="button" data-mini="true" class="ui-btn-left" data-theme="c" >Show full list</a>';

        $("#full_list_button").bind("click", function() { displContactList.updateList(); div.innerHTML = ""; });

        $("#full_list_button").button();

    }

}

Dispositivos Testados

  • Dispositivos Móveis:
    • Apple iPad* 2 tablet (iOS 5.1.1)
    • Sony Ericsson* Go smartphone (Android 2.3.7)
    • Samsung Galaxy Tab* 2 tablet (Android 4.0.3)
Catégories:
Reportez-vous à notre Notice d'optimisation pour plus d'informations sur les choix et l'optimisation des performances dans les produits logiciels Intel.