Compartilhar via


Microsoft Office

Explorando a API JavaScript para Office: Acesso a dados e eventos

Stephen Oliver
Eric Schmidt

 

Este artigo é o segundo de uma série de instruções passo a passo detalhadas da API JavaScript para Office. A parte 1 (disponível em msdn.microsoft.com/magazine/jj891051) fornece uma ampla visão geral do modelo de objeto. Este artigo parte de onde a parte 1 parou, com um detalhado passo a passo sobre como acessar o conteúdo do arquivo e uma análise do modelo de evento.

Em toda esta série, mencionamos com frequência a documentação de referência da API JavaScript para Office. Você pode encontrar a documentação oficial, exemplos de código e recursos da comunidade na Central de desenvolvedores de Aplicativos para Office e SharePoint do MSDN (dev.office.com).

Acessando o conteúdo do arquivo do Office em um aplicativo para o Office

A API JavaScript para Office fornece várias maneiras básicas de acessar dados em um arquivo do Office: você pode obter ou definir os dados atualmente selecionados, ou pode obter o arquivo inteiro. Esse nível de acesso a dados pode parecer simples e, na verdade, ambas as técnicas são bastante simples de usar. No entanto, há um amplo grau de flexibilidade e personalização em ambas as técnicas, proporcionando-lhe muitas possibilidades para seus aplicativos.

Além do acesso a dados selecionados ou todo o arquivo, a API JavaScript para Office também permite associar dados ou manipular partes XML personalizadas no documento. Vejamos mais de perto essas técnicas para trabalhar com conteúdo do Office.

Como obter e definir dados selecionados

Como mencionamos anteriormente, o objeto de documento concede a um aplicativo o acesso aos dados no arquivo. Para aplicativos com painel de tarefas e conteúdo, podemos obter ou definir o conteúdo selecionado em um arquivo do Office usando os métodos Document.getSelectedDataAsync e Document.setSelectedDataAsync.

Os dois métodos podem manipular vários tipos de formatos de dados que controlamos quando os chamamos. Os métodos getSelectedDataAsync e setSelectedDataAsync têm um parâmetro, coercionType, que extrai uma constante da enumeração Office.CoercionType. O parâmetro coercionType especifica o formato de dados de conteúdo a ser obtido ou definido. Dependendo do valor do parâmetro coercionType, podemos selecionar dados como texto sem formatação, uma tabela, uma matriz, HTML ou até mesmo OOXML (Office Open XML) "bruto". (Note que obter e definir o texto como HTML ou OOXML tem suporte apenas no Word 2013 até o momento da publicação deste artigo).

Nem sempre você tem de especificar um coercionType ao usar getSelectedDataAsync e setSelectedDataAsync. O coercionType é inferido do contexto sempre que possível. Por exemplo, se você passar um literal de string em uma chamada para setSelectedDataAsync, o coercionType padrão será "text". Se você passar os mesmos dados como uma matriz de matrizes, o coercionType padrão seria "matrix".

Daremos alguns exemplos do quão poderosos esses métodos simples podem ser, principalmente usando o método de setSelectedDataAsync. Vamos começar com um código que insere um texto simples em um documento do Word:

// Define some data to set in the document.
var booksToRead = "Anabasis by Xenophon; \n" +
  "Socrates' Apology by Plato; \n" +
  "The Illiad by Homer.";
// Set some data to the document as simple text.
Office.context.document.setSelectedDataAsync(
  booksToRead,
  { coercionType: Office.CoercionType.Text },
  function (result) {
    // Access the results, if necessary.
});

A Figura 1 mostra o resultado.

Results of Inserting Data as Simple Text
Figura 1 Resultados da inserção de dados como texto simples

Agora vamos alterar o exemplo para inserirmos o texto como um tipo de coerção "matrix". Matrix é uma matriz de matrizes que é inserida como um intervalo de células simples (Excel) ou tabela simples (Word).

Quando inserido no Word, o código insere uma tabela sem formatação de duas colunas sem cabeçalho. Cada item da matriz de primeiro nível representa uma linha da tabela resultante; cada item de uma submatriz contém dados de uma célula na linha:

// Define a matrix of data to set in the document.
var booksToRead = [["Xenophon", "Anabasis"],
  ["Plato", "Socrates' Apology"],
  ["Homer", "The Illiad"]];
// Set some data to the document as an unformatted table.
Office.context.document.setSelectedDataAsync(
  booksToRead,
  { coercionType: Office.CoercionType.Matrix },
  function (result) {
    // Access the results, if necessary.
});

A Figura 2 mostra o resultado.

Results of Inserting Data as a Matrix
Figura 2 Resultados da inserção de dados como matriz

Além do tipo de coerção de matriz, podemos obter ou definir os dados como uma tabela usando um objeto TableData. Isso nos permite fornecer um pouco mais de formatação aos resultados — neste caso específico, uma linha de cabeçalho. Acessamos a linha de cabeçalho e o conteúdo de um objeto TableData usando as propriedades de cabeçalhos e linhas, respectivamente.

Além disso, com o objeto TableData, você pode especificar um subconjunto de dados para inserir usando os parâmetros startRow e startColumn. Isso permite definir os dados em uma única coluna de uma tabela de cinco colunas existente, por exemplo. Veremos os parâmetros startRow e startColumn em maior profundidade no próximo artigo desta série.

Observação: se a seleção no documento for uma tabela, a forma de seleção deverá coincidir com os dados que estão sendo inseridos (a menos que você especifique os parâmetros startRow e startColumn). Ou seja, se os dados que estão sendo inseridos forem uma tabela 2 x 2 e a seleção no documento forem células 3 x 2 em uma tabela, o método falhará. Isso também se aplica à inserção de dados como matriz.

Como o tipo de coerção de matriz, as propriedades de cabeçalhos e linhas retornam uma matriz de matrizes, onde cada item da primeira matriz é uma linha de dados e cada item de uma submatriz contém uma célula de dados na tabela, como você pode ver na Figura 3.

Figura 3 Inserindo dados em um documento como tabela

// Define some tabular data to set in the document,
// including a header row.
var booksToRead = new Office.TableData();
booksToRead.headers = [["Author", "Title"]];
booksToRead.rows = [["Xenophon", "Anabasis"],
  ["Plato", "Socrates' Apology"],
  ["Homer", "The Illiad"]];
// Set some data to the document as a table with a header.
Office.context.document.setSelectedDataAsync(
  booksToRead,
  { coercionType: Office.CoercionType.Table },
  function (result) {
    // Access the results, if necessary.
});

A Figura 4 mostra o resultado do código na Figura 3.

Results of Inserting Data as a Table
Figura 4 Resultados da inserção de dados como tabela

No próximo exemplo, vamos inserir os mesmos dados, desta vez formatados como HTML e usando a coerção Office.CoercionType.HTML. Agora podemos adicionar formatação extra aos dados inseridos, como estilos CSS, conforme mostrado na Figura 5.

Figura 5 Inserindo dados em um documento como HTML

// Define some HTML data to set in the document,
// including header row, text formatting and CSS styles.
var booksToRead =
  "<table style='font-family:Segoe UI'>" +
    "<thead style='background-color:#283E75;color:white'>" +
      "<tr><th>Authors</th><th>Books</th></tr>" +
    "</thead>" +
    "<tbody>" +
      "<tr><td>Xenophon</td><td><u>Anabasis</u></td></tr>" +
      "<tr><td>Plato</td><td><u>Socrates' Apology</u></td></tr>" +
      "<tr><td>Homer</td><td><u>The Iliad</u></td></tr>" +
    "</tbody>" +
  "</table>";
// Set some data to the document as a table with styles applied.
Office.context.document.setSelectedDataAsync(
  booksToRead,
  { coercionType: Office.CoercionType.Html },
    function (result) {
    // Access the results, if necessary.
});

A Figura 6 mostra o resultado do código na Figura 5.

Results of Inserting Data as HTML
Figura 6 Resultados da inserção de dados como HTML

Finalmente, também podemos inserir texto no documento como OOXML, o que nos permite personalizar bem os dados e usar muitos tipos de conteúdo mais avançados no Word (SmartArt ou imagens embutidas, como dois exemplos).

A tabela de dados em que estamos trabalhando, quando representada como OOXML e armazenada no literal da string, é semelhante ao código na Figura 7 (observação: apenas uma parte da tabela é apresentada, para abreviar).

Figura 7 Um trecho OOXML que representa uma tabela do Word, armazenado como um literal de string JavaScript

var newTable = "<w:tbl>" +
  "<w:tblPr>" +
    "<w:tblStyle w:val=\"TableGrid\"/>" +
    "<w:tblW w:w=\"0\" w:type=\"auto\"/>" +
    "<w:tblBorders>" +
      "<w:top w:val=\"single\" w:sz=\"4\" w:space=\"0\"" +
        "w:color=\"283E75\"/>" +
      "<w:left w:val=\"single\" w:sz=\"4\" w:space=\"0\"" +
        "w:color=\"283E75\"/>" +
      "<w:bottom w:val=\"single\" w:sz=\"4\" w:space=\"0\"" +
        "w:color=\"283E75\"/>" +
      "<w:right w:val=\"single\" w:sz=\"4\" w:space=\"0\"" +
        "w:color=\"283E75\"/>" +
      "<w:insideH w:val=\"single\" w:sz=\"4\" w:space=\"0\"" +
        "w:color=\"283E75\"/>" +
      "<w:insideV w:val=\"single\" w:sz=\"4\" w:space=\"0\"" +
        "w:color=\"283E75\"/>" +
      "</w:tblBorders>" +
    "<w:tblLook w:val=\"04A0\" w:firstRow=\"1\" w:lastRow=\"0\"" +
      "w:firstColumn=\"1\" w:lastColumn=\"0\""  +
      "w:noHBand=\"0\" w:noVBand=\"1\"/>" +
  "</w:tblPr>" +
  "<w:tblGrid>" +
    "<w:gridCol w:w=\"4675\"/>" +
    "<w:gridCol w:w=\"4675\"/>" +
  "</w:tblGrid>" +
  "<w:tr w:rsidR=\"00431544\" w:rsidTr=\"00620187\">" +
    "<w:tc>" +
      "<w:tcPr>" +
        "<w:tcW w:w=\"4675\" w:type=\"dxa\"/>" +
        "<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"283E75\"/>" +
      "</w:tcPr>" +
      "<w:p w:rsidR=\"00431544\" w:rsidRPr=\"00236B94\""  +
        "w:rsidRDefault=\"00431544\" w:rsidP=\"00620187\">" +
        "<w:pPr>" +
          "<w:rPr>" +
            "<w:b/>" +
            "<w:color w:val=\"FEFEFE\"/>" +
          "</w:rPr>" +
        "</w:pPr>" +
        "<w:r w:rsidRPr=\"00236B94\">" +
          "<w:rPr>" +
            "<w:b/>" +
            "<w:color w:val=\"FEFEFE\"/>" +
          "</w:rPr>" +
          "<w:t>Authors</w:t>" +
        "</w:r>" +
      "</w:p>" +
    "</w:tc>" +
    "<w:tc>" +
      "<w:tcPr>" +
        "<w:tcW w:w=\"4675\" w:type=\"dxa\"/>" +
        "<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"283E75\"/>" +
      "</w:tcPr>" +
      "<w:p w:rsidR=\"00431544\" w:rsidRPr=\"00236B94\"" +
        "w:rsidRDefault=\"00431544\" w:rsidP=\"00620187\">" +
        "<w:pPr>" +
          "<w:rPr>" +
            "<w:b/>" +
            "<w:color w:val=\"FEFEFE\"/>" +
          "</w:rPr>" +
        "</w:pPr>" +
        "<w:r w:rsidRPr=\"00236B94\">" +
          "<w:rPr>" +
            "<w:b/>" +
            "<w:color w:val=\"FEFEFE\"/>" +
          "</w:rPr>" +
          "<w:t>Books</w:t>" +
        "</w:r>" +
      "</w:p>" +
    "</w:tc>" +
  "</w:tr>" +
  "<w:tr w:rsidR=\"00431544\" w:rsidTr=\"00620187\">" +
    "<w:tc>" +
      "<w:tcPr>" +
        "<w:tcW w:w=\"4675\" w:type=\"dxa\"/>" +
      "</w:tcPr>" +
      "<w:p w:rsidR=\"00431544\" w:rsidRDefault=\"00431544\"" +
        "w:rsidP=\"00620187\">" +
        "<w:r>" +
          "<w:t>Xenophon</w:t>" +
        "</w:r>" +
      "</w:p>" +
    "</w:tc>" +
    "<w:tc>" +
      "<w:tcPr>" +
        "<w:tcW w:w=\"4675\" w:type=\"dxa\"/>" +
      "</w:tcPr>" +
      "<w:p w:rsidR=\"00431544\" w:rsidRDefault=\"00431544\"" +
        "w:rsidP=\"00620187\">" +
        "<w:r>" +
          "<w:t>Anabasis</w:t>" +
        "</w:r>" +
      "</w:p>" +
    "</w:tc>" +
  "</w:tr>" +
  // The rest of the code has been omitted for the sake of brevity.
"</w:tbl>";

Esta técnica também requer um alto grau de familiaridade com XML e as estruturas descritas pelo padrão OOXML (ECMA-376) em particular. Ao definir OOXML em um documento, os dados devem ser armazenados como string (objetos de documento HTML não podem ser inseridos) que contém todas as informações necessárias — incluindo as relações e partes do documento relacionado no pacote de formatos de arquivo. Assim, ao inserir um tipo de conteúdo mais avançado no Word usando OOXML, você deve lembrar de manipular os dados OOXML de acordo com as práticas recomendadas do uso de OOXML e Open Packaging Conventions.

Na Figura 8, contornamos esse problema obtendo os dados como OOXML primeiro, concatenando nossos dados com o OOXML do documento (manipulando os dados recebidos e os novos dados como strings) e inserindo o OOXML de volta no documento. (Com efeito, parte do motivo pelo qual esse código funciona é porque ainda não adicionamos conteúdo que requer a adição ou alteração de qualquer relacionamento ou partes do documento no arquivo.)

Figura 8 Inserindo dados em um documento como tabela usando OOXML

// Get the OOXML for the data at the point of insertion
// and add a table at the beginning of the selection.
Office.context.document.getSelectedDataAsync(
  Office.CoercionType.Ooxml,
  {
    valueFormat: Office.ValueFormat.Formatted,
    filterType: Office.FilterType.All
  },
  function (result) {
    if (result.status == "succeeded") {
      // Get the OOXML returned from the getSelectedDataAsync call.
      var selectedData = result.value.toString();
      // Define the new table in OOXML.
      var newTable = "<!--Details omitted for brevity.-->";
      // Find the '<w:body>' tag in the returned data—the tag
      // that represents the body content of the selection, contained
      // within the main document package part (/word/document.xml)—
      // and then insert the new table into the OOXML at that point.
      var newString = selectedData.replace(
        "<w:body>",
        "<w:body>" + newTable,
        "gi");
        // Insert the data back into the document with the table added.
        Office.context.document.setSelectedDataAsync(
          newString,
          { coercionType: Office.CoercionType.Ooxml },
          function () {
        });
    }
});

A Figura 9 mostra os resultados do código na Figura 8.

Results of Inserting Data as OOXML
Figura 9 Resultados da inserção de dados como OOXML

Observação: uma boa maneira de aprender a manipular o OOXML de um aplicativo é adicionar o conteúdo com o qual deseja trabalhar usando a interface de usuário (por exemplo, inserir SmartArt clicando em Inserir | Ilustrações | SmartArt), obter o OOXML do conteúdo usando getSelectedDataAsync e ler os resultados. Veja o post "Inserting images with apps for Office" no blog em bit.ly/SeU3MS para obter mais detalhes.

Obtendo todo o conteúdo do arquivo

Obter ou definir dados no ponto de seleção é bom, mas há situações em que é necessário obter todo o conteúdo de um arquivo. Por exemplo, um aplicativo pode precisar obter todo o conteúdo do documento como texto, analisá-lo e representá-lo em um gráfico de bolhas. Como outro exemplo, um aplicativo pode precisar enviar todo o conteúdo do arquivo para um serviço Web remoto para impressão remota ou envio de fax.

A API JavaScript para Office fornece apenas a funcionalidade para essas situações. Usando a API de JavaScript, um aplicativo pode criar uma cópia do arquivo em que está inserido, separar a cópia em trechos de dados dimensionados ou "fatias" (até 4 MB) e ler os dados dentro dessas fatias.

O processo para obter todo o conteúdo do arquivo essencialmente inclui três etapas:

  1. Para aplicativos inseridos no Word ou PowerPoint, o aplicativo chama o método Document.getFileAsync, que retorna um objeto File que corresponde a uma cópia do arquivo.
  2. Quando o aplicativo tiver uma referência para o arquivo, ele poderá chamar o método File.getSliceAsync para acessar fatias específicas dentro do arquivo, passando o índice da fatia a ser obtida. Se isso for feito usando um loop, o código de chamada deve ter cuidado em como ele lida com fechamentos.
  3. Finalmente, o aplicativo deve fechar o objeto File quando terminar de usá-lo, chamando o método File.closeAsync. Apenas dois arquivos podem permanecer na memória por vez; tentar abrir um terceiro arquivo usando Document.getFileAsync gera o erro "Ocorreu um erro interno".

Na Figura 10, obtemos um documento do Word em trechos de 1 KB, iteramos sobre cada trecho do arquivo e fechamos o arquivo quando terminamos.

Figura 10 Obtendo todo o conteúdo de um arquivo como texto e iterando sobre as fatias

// Get all of the content from a Word document in 1KB chunks of text.
function getFileData() {
  Office.context.document.getFileAsync(
  Office.FileType.Text,
  {
    sliceSize: 1000
  },
  function (asyncResult) {
    if (asyncResult.status === 'succeeded') {
      var myFile = asyncResult.value,
        state = {
          file: myFile,
          counter: 0,
          sliceCount: myFile.sliceCount
        };
      getSliceData(state);
    }
  });
}
// Get a slice from the file, as specified by
// the counter contained in the state parameter.
function getSliceData(state) {
  state.file.getSliceAsync(
    state.counter,
    function (result) {
    var slice = result.value,
      data = slice.data;
    state.counter++;
    // Do something with the data.
    // Check to see if the final slice in the file has
    // been reached—if not, get the next slice;
    // if so, close the file.
    if (state.counter < state.sliceCount) {
      getSliceData(state);
    }
    else {
      closeFile(state);
    }
  });
}
// Close the file when done with it.
function closeFile(state) {
  state.file.closeAsync(
    function (results) {
      // Inform the user that the process is complete.
  });
}

Para obter mais informações sobre como obter todo o conteúdo do arquivo em um aplicativo para Office, consulte a página de documentação "How to: Get the whole document from an app for PowerPoint”, em bit.ly/12Asi4x.

Obtendo dados de tarefa, exibição e recurso de um projeto

Para aplicativos com painel de tarefas inseridos no Project, a API JavaScript para Office contém métodos adicionais para ler os dados do projeto ativo e da tarefa, recurso ou exibição selecionada. O script project-15.js estende o office.js e também adiciona eventos de alteração de seleção para tarefas, recursos e exibições. Por exemplo, quando o usuário seleciona uma tarefa no modo de exibição Planejador de Equipe, um aplicativo pode integrar e exibir em um único lugar o trabalho restante programado para essa tarefa, quem está disponível para trabalhar nele, bem como os projetos relacionados em outras listas de tarefas do SharePoint ou do Project Server que podem afetar o cronograma.

Um aplicativo com painel de tarefas inserido em um projeto só tem acesso de leitura ao conteúdo do projeto. Mas, como um aplicativo com painel de tarefas está no coração de uma página da Web, ele pode ler e gravar em aplicativos externos usando JavaScript e protocolos como REST (Representational State Transfer). Por exemplo, a documentação de aplicativos para Office e SharePoint inclui um aplicativo de exemplo para o Project Professional que usa jQuery com o serviço de relatório OData no Project para comparar dados de custo total e trabalho para o projeto ativo, com as médias para todos os projetos do Project Web App (veja a Figura 11).

A Task Pane App that Uses jQuery with an OData Reporting Service
Figura 11 Um aplicativo com painel de tarefas que usa jQuery com um serviço de relatório OData

Para obter mais informações, consulte a página de documentação "How to: Create a Project app that uses REST with an on-premises Project Server OData service”, em bit.ly/T80W2H.

Como ProjectDocument estende o objeto Document, o objeto Office.context.document captura uma referência ao projeto ativo — semelhante aos aplicativos inseridos em outros aplicativos host. Os métodos assíncronos disponíveis no Project têm assinaturas semelhantes aos outros métodos na API JavaScript para Office. Por exemplo, o método getProjectFieldAsync tem três parâmetros:

  • fieldId: especifica o campo a ser retornado no objeto para o parâmetro callback. A enumeração Office.ProjectProjectFields contém 12 campos, como GUID do projeto, data de início, data de término e (se houver) a URL do Project Server ou a URL da lista de tarefas do SharePoint.
  • asyncContext: (opcional) é qualquer tipo definido pelo usuário retornado no objeto asyncResult.
  • callback: contém uma referência a uma função que é executada quando a chamada retorna e contém opções para lidar com o êxito ou a falha.

Como você pode ver na Figura 12, os métodos específicos aos aplicativos no Project são usados da mesma forma para aplicativos hospedados em outros aplicativos. No fragmento de script, uma função definida localmente chama uma rotina que exibe uma mensagem de erro no aplicativo. O script não usa o parâmetro asyncContext.

Figura 12 Obtendo o GUID de um campo de um painel de tarefas inserido em um projeto

var _projectUid = "";
// Get the GUID of the active project.
function getProjectGuid() {
  Office.context.document.getProjectFieldAsync(
    Office.ProjectProjectFields.GUID,
    function (asyncResult) {
      if (asyncResult.status == Office.AsyncResultStatus.Succeeded) {
        _projectUid = asyncResult.value.fieldValue;
        }
      else {
        // Display error message to user.
      }
    }
  );
}

Embora o método getProjectFieldAsync possa obter somente 12 campos para o projeto geral, o método getTaskFieldAsync pode obter qualquer um dos 282 campos diferentes para uma tarefa usando a enumeração ProjectTaskFields. E o método getResourceFieldAsync pode obter qualquer um dos 200 campos para um recurso usando a enumeração ProjectResourceFields. Métodos mais gerais no objeto ProjectDocument incluem getSelectedDataAsync, que retorna dados de texto selecionados em qualquer um dos modos de exibição com suporte, e getTaskAsync, que retorna vários itens de dados gerais para uma tarefa selecionada. Aplicativos com painel de tarefas podem funcionar com 16 modos de exibição diferentes no Project.

Além disso, aplicativos com painel de tarefas no Project podem adicionar ou remover manipuladores de eventos quando o usuário altera uma exibição, seleciona uma tarefa ou um recurso.

Eventos em um aplicativo para o Office

A API JavaScript para Office permite criar aplicativos que respondem melhor em eventos. O modelo de evento para a API oferece suporte a quatro cenários de evento-chave fundamentais para o desenvolvimento de aplicativos para o Office (abordado mais tarde). Entender estes quatro cenários lhe dará uma sólida compreensão do modelo de evento para a API.

Dito isso, o modelo de evento para aplicativos para o Office é completamente consistente; então, saber o design comum para manipulação de eventos irá completar sua compreensão deste importante conceito.

No que diz respeito ao design comum para eventos em aplicativos para a API do Office, os seguintes objetos têm eventos associados a eles:

  • Associação
  • CustomXMLPart
  • Document
  • RoamingSettings (aplicativos de email)
  • Settings

Além dos eventos associados a ele, cada um dos objetos listados tem dois métodos para lidar com seus eventos:

  • addHandlerAsync
  • removeHandlerAsync

Como o método removeHandlerAsync simplesmente cancela a assinatura de um manipulador de eventos e sua assinatura é quase idêntica à do addHandlerAsync, na próxima seção, focaremos nossa atenção apenas a addHandlerAsync.

Observação: há uma diferença muito importante entre os métodos remove­HandlerAsync e addHandlerAsync. O parâmetro handler é opcional para removeHandlerAsync. Se não for especificado, todos os manipuladores para o tipo de evento especificado serão removidos.

O método AddHandlerAsync

O método addHandlerAsync conecta um manipulador de eventos ao evento especificado e tem a mesma assinatura para cada objeto que o implementa:

objectName.addHandlerAsync(eventType, handler [, options], callback);

Agora vamos falar sobre os parâmetros desse método.

Parâmetro EventType O parâmetro eventType necessário extrai uma enumeração EventType, que informa ao método qual tipo de evento conectar.

Parâmetro Handler O parâmetro eventType é seguido do parâmetro handler. Esse parâmetro pode ser uma função nomeada ou uma função embutida anônima. Observe que, assim como o modelo de evento para muitas linguagens de programação, os aplicativos para o tempo de execução do Office invoca o manipulador e passa um argumento de objeto de evento como o único parâmetro. Além disso, se você usar uma função embutida anônima para o parâmetro handler, a única maneira de remover o manipulador é remover todos os manipuladores do evento chamando removeHandler­Async e não especificar o parâmetro handler.

Parâmetro Options Como todas as funções assíncronas nos aplicativos para a API do Office, você pode especificar um objeto que contém parâmetros opcionais, mas para todos os métodos addHandlerAsync, o único parâmetro opcional que você pode especificar é asyncContext. Ele é fornecido como uma maneira de passar os dados que você quiser pelo método assíncrono que você pode recuperar dentro do retorno de chamada.

Parâmetro Callback Esse parâmetro age exatamente como o faz em outros locais dos aplicativos para a API do Office, com uma exceção importante: a propriedade value do objeto AsyncResult. Como dito anteriormente neste artigo, quando o tempo de execução chama um retorno de chamada, ele passa um objeto Async­Result e você usa a propriedade value do objeto AsyncResult para obter o valor de retorno da chamada assíncrona. No caso de retornos de chamada no método addHandlerAsync, o valor do objeto Async­Result é sempre indefinido.

A Figura 13 demonstra como o código do método addHandlerAsync para o evento DocumentSelectionChanged (o código presume que você tenha um elemento <div> com um valor de atributo de identificação de "message").

Figura 13 Conectando um manipulador de eventos para o evento DocumentSelection­Changed usando o método Document.addHandlerAsync

Office.initialize = function (reason) {
  $(document).ready(function () {       
    Office.context.document.addHandlerAsync(
      Office.EventType.DocumentSelectionChanged, onDocSelectionChanged,
        addHandlerCallback);
      Office.context.document.addHandlerAsync(
        Office.EventType.DocumentSelectionChanged, onDocSelectionChanged2,
        addHandlerCallback2);
  });
};
function onDocSelectionChanged(docSelectionChangedArgs) {
  write("onDocSelectionChanged invoked each event.");
}
function onDocSelectionChanged2(docSelectionChangedArgs) {
  write("onDocSelectionChanged2 invoked each event.");
}
function addHandlerCallback(asyncResult) {
  write("addHandlerCallback only called once on app initialize.");
}
function addHandlerCallback2(asyncResult) {
  write("addHandlerCallback2 only called once on app initialize.");
}
function write(message) {$('#message').append(message + "\n");

Quando o aplicativo é inicializado, o código na Figura 13 conecta as funções dos manipuladores onDocSelectionChanged e onDocSelectionChanged2 ao evento Document­SelectionChanged, mostrando que você pode ter mais de um manipulador de eventos para o mesmo evento. Ambos os manipuladores simplesmente gravam no <div> "message" quando o evento DocumentSelectionChanged dispara.

As chamadas para addHandlerAsync incluem retornos de chamada addHandlerCallback e addHandlerCallback2, respectivamente. Os retornos de chamada também gravam no <div> "message", mas são chamados apenas uma vez quando addHandlerAsync é concluído.

Da mesma forma, você pode usar o método addHandlerAsync para conectar manipuladores de eventos para qualquer evento na API JavaScript para Office.

Cenários-chave do modelo de evento para aplicativo para o Office

Como mencionado, na API JavaScript para Office, há quatro cenários de evento-chave que você deve saber ao considerar o modelo de eventos de aplicativos para o Office. Todos os eventos na API cairão em um destes quatro cenários de evento-chave:

  • Eventos Office.initialize
  • Eventos de mudança de seleção no nível de documento
  • Eventos de seleção e alteração de dados no nível de associação
  • Eventos de alteração de configurações

Eventos Office.initialize De longe o evento mais comum na API JavaScript para Office que você encontrará é o evento Office.initialize. O evento initialize acontece para todos os aplicativos que você criar para o Office. Na verdade, é a primeira parte de seu código que o tempo de execução executa.

Se você verificar o código de inicialização que o Visual Studio 2012 fornece para os novos aplicativos para o projeto Office, você verá que as primeiras linhas do código de inicialização no arquivo ProjectName.js do seu aplicativo conecta um manipulador de eventos ao evento Office.initialize, conforme mostrado aqui:

// This function is run when the app is ready to
// start interacting with the host application;
// it ensures the DOM is ready before adding click handlers to buttons.
Office.initialize = function (reason) { /* handler code */ };

Como você sabe da seção de hierarquia de modelos Object no artigo anterior, o objeto Office é o objeto de nível superior na API JavaScript para Office e representa a instância do seu aplicativo no tempo de execução. O evento Initialize dispara quando os aplicativos para o tempo de execução do Office estão completamente carregados e prontos para interação com seu aplicativo. Assim, o manipulador de eventos Initialize é essencialmente o "handshake" entre seu aplicativo e o tempo de execução que deve ocorrer antes da execução do resto de seu código.

A função que você deve fornecer como manipulador para o evento Office.initialize leva um único argumento — uma enumeração InitializationReason. A enumeração Initialization­Reason tem apenas duas enumerações — Inserted e documentOpened:

  • Inserted indica que o aplicativo está sendo inicializado porque acaba de ser inserido no documento.
  • documentOpened significa que o aplicativo está sendo inicializado porque o documento que já tinha o aplicativo inserido acaba de ser aberto.

O tempo de execução passará na enumeração InitializationReason como o único argumento para a função de manipulador. A partir daí, você pode ramificar como seu código irá reagir dependendo do motivo.

Esta é uma ideia de como isso poderia funcionar:

Office.initialize = function (reason) {
  // Display initialization reason.
  if (reason == "inserted")
  write("The app was just inserted.");
  if (reason == "documentOpened")
  write(
    "The app is already part of the document.");
}
// Function that writes to a div with
// id='message' on the page.
function write(message){
  document.getElementById(
  'message').innerText += message;
}

Observação: o trecho de código anterior presume que você tem um elemento <div> com um valor de atributo de identificação de "message".

Curiosamente, você não precisa incluir nada na função que você fornecer como manipulador, mas a função deve estar presente, ou seu aplicativo lançará um erro quando for iniciado.

A propósito, o manipulador de eventos para o evento Office.initialize é um bom lugar para inicializar outras estruturas que você pode usar em seu aplicativo, como jQuery. Novamente, o código de inicialização que o Visual Studio fornece para novos aplicativos para projetos do Office, você verá algo parecido com o código na Figura 14.

Figura 14 Inicializando outras estruturas dentro do manipulador de eventos Office.initialize

Office.initialize = function (reason) {
  $(document).ready(function () {
    $('#getDataBtn').click(function () { getData('#selectedDataTxt'); });
    // If setSelectedDataAsync method is supported
    // by the host application, setDatabtn is hooked up
    // to call the method, else setDatabtn is removed.
    if (Office.context.document.setSelectedDataAsync) {
        $('#setDataBtn').click(function () { setData('#selectedDataTxt'); });
    }
    else {
      $('#setDataBtn').remove();
    }
  });
};

O evento .ready do jQuery é tratado dentro do manipulador de eventos Office.initialize. Isso garante que a API JavaScript para Office seja carregada e pronta antes de o código JQuery chamá-la.

Eventos de mudança de seleção no nível de documento Esses eventos ocorrem quando a seleção no documento muda de uma seleção para outra. Por exemplo, quando o usuário clica fora da seleção atual em um documento do Word para um intervalo de texto, ou objeto ou local em outra parte do documento, um evento é disparado no nível de documento para a mudança de seleção.

O código a seguir ilustra como responder a uma mudança da seleção atual:

function addEventHandlerToDocument() {
    Office.context.document.addHandlerAsync(
      Office.EventType.DocumentSelectionChanged,
      MyHandler);
  }
  function MyHandler(eventArgs) {
    doSomethingWithDocument(eventArgs.document);

Eventos de seleção e alteração de dados no nível de associação Associações em aplicativos para o modelo de objeto do Office são uma maneira de acessar consistentemente uma área específica em um documento (ou planilha) estabelecendo um vínculo, ou uma associação, a uma região exclusivamente nomeada no documento. Para trabalhar com uma associação, você cria uma primeiro usando um dos métodos fornecidos da API. Depois você pode se referir à associação específica que você criou usando seu identificador exclusivo.

As associações também disparam eventos, e seu aplicativo pode responder a esses eventos conforme necessário. Em particular, as associações disparam um evento quando a seleção é alterada na área de associação e quando dados são alterados na área de associação. Os dois trechos de código a seguir mostram como tratar alterações de seleção e de dados em determinada associação (ambos presumem que você tenha um elemento <div> com um valor de atributo de identificação de "message").

Respondendo ao evento Binding.bindingSelectionChanged:

function addEventHandlerToBinding() {
  Office.select("bindings#MyBinding").addHandlerAsync(
    Office.EventType.BindingSelectionChanged,
    onBindingSelectionChanged);
}
function onBindingSelectionChanged(eventArgs) {
  write(eventArgs.binding.id + " has been selected.");
}
// Function that writes to a div with id='message' on the page.
function write(message){
  document.getElementById('message').innerText += message;
}

Respondendo ao evento Binding.bindingDataChanged:

function addEventHandlerToBinding() {
  Office.select("bindings#MyBinding").addHandlerAsync(
    Office.EventType.BindingDataChanged, onBindingDataChanged);
}
function onBindingDataChanged(eventArgs) {
  write("Data has changed in binding: " + eventArgs.binding.id);
}
// Function that writes to a div with id='message' on the page.
function write(message){
  document.getElementById('message').innerText += message;
}

Eventos de alteração de configurações Os aplicativos para o modelo de objeto do Office fornece uma maneira para os desenvolvedores manterem as configurações relacionadas ao seu aplicativo. O objeto Settings atua como um recipiente de propriedades em que configurações personalizadas do aplicativo são armazenadas como pares de chave/valor. O objeto Settings também tem um evento associado a ele — Settings.settingsChanged — que dispara quando uma configuração armazenada é alterada.

Para obter mais informações sobre o evento Settings.settingsChanged, consulte a documentação do MSDN da API JavaScript para Office em bit.ly/U92Sbe.

A seguir: Tópicos mais avançados

Neste segundo artigo da série, revisamos os conceitos básicos da obtenção e definição de conteúdo de arquivos do Office em um aplicativo para o Office. Mostramos como obter e definir os dados de seleção e como obter todos os dados do arquivo. Vimos como obter dados de projeto, tarefa, exibição e recurso de um aplicativo para o Project. Finalmente, vimos os eventos na API JavaScript para Office e como codificar de acordo com eles.

Observação: gostaríamos de agradecer a Jim Corbin, escritor de programação na Divisão do Office, pela contribuição em grande parte do conteúdo sobre aplicativos para o Project.

Em seguida, analisaremos mais atentamente alguns tópicos mais avançados na API JavaScript do Office: vinculações de dados e partes XML personalizadas.

Stephen Oliver é um escritor de programação na Divisão do Office e um Microsoft Certified Professional Developer (SharePoint 2010). Escreve a documentação do desenvolvedor para Serviços do Excel e Word Automation Services, bem como para PowerPoint Automation Services. Ajudou a organizar e desenvolver o site Excel Mashup, em ExcelMashup.com.

Eric Schmidt é um escritor de programação na Divisão do Office. Criou vários exemplos de código para aplicativos para o Office, incluindo o popular “Manter as configurações personalizadas”. Além disso, escreveu artigos e criou vídeos sobre outros produtos e tecnologias na programação do Office.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Mark Brewster, Shilpa Kothari e Juan Balmori Labra
Mark Brewster graduado como bacharel em matemática e ciência da computação pela Universidade do Arizona em 2008 e desenvolve software na Microsoft há quatro anos. Ele anda de bicicleta por diversão e para economizar, e gosta de beber cerveja e ouvir discos.

Shilpa Kothari (Bhavsar) é engenheira de software em teste da Microsoft. Ela trabalhou em vários produtos da Microsoft, como Bing Mobile, Visual Studio e Office. Ela é apaixonada por controle de qualidade de software e experiência do usuário e pode ser contatada através do email shilpak@microsoft.com.

Juan Balmori Labra é gerente de programa, que trabalhou nos últimos três anos na API de JavaScript do Microsoft Office. Ele trabalhou anteriormente na versão Office 2010, entregando Serviços Corporativos de Conectividade e Duet. Antes de ir em busca de seu sonho de se mudar para Redmond, Juan trabalhou na Microsoft México como o arquiteto principal da prática de consultoria para o setor público.