Linguagem do Modelo de Cartões Adaptáveis

A modelagem habilita a separação de dados do layout em um Cartão Adaptável. A linguagem do modelo é a sintaxe usada para criar um modelo.

Leia a Visão geral da Modelagem de Cartão Adaptável

Importante

Alterações da falha na versão Release Candidate de maio de 2020

Temos trabalhado duro para lançar a modelagem e, por fim, estamos na reta final. Com a proximidade do lançamento, tivemos que fazer algumas pequenas alterações da falha.

Alterações da falha a partir de maio de 2020

  1. A sintaxe de associação foi alterada de {...} para ${...}
    • Por exemplo: "text": "Hello {name}" se torna "text": "Hello ${name}"

Associação a dados

Escrever um modelo é tão simples quanto substituir o conteúdo "não estático" do cartão por "expressões de associação".

Conteúdo do cartão estático

{
   "type": "TextBlock",
   "text": "Matt"
}

Conteúdo do modelo

{
   "type": "TextBlock",
   "text": "${firstName}"
}
  • As expressões de associação podem ser colocadas praticamente em qualquer lugar em que o conteúdo estático possa ser colocado
  • A sintaxe de associação começa com ${ e termina com }. Por exemplo, ${myProperty}
  • Use Dot-notation para acessar os subobjetos de uma hierarquia de objetos. Por exemplo, ${myParent.myChild}
  • A manipulação normal de null garante que você não obterá exceções se acessar uma propriedade nula em um grafo de objetos
  • Use a Sintaxe do indexador para recuperar propriedades por chave ou itens em uma matriz. Por exemplo, ${myArray[0]}

Fornecer os dados

Agora que você tem um modelo, é necessário fornecer os dados que o completam. Você tem duas opções para fazer isso:

  1. Opção A: embutidos dentro do conteúdo do modelo. Você pode fornecer os dados embutidos dentro do conteúdo do modelo AdaptiveCard. Para fazer isso, basta adicionar um atributo $data ao objeto AdaptiveCard raiz.
  2. Opção B: como um objeto de dados separado. Com essa opção, você fornece dois objetos separados para o SDK de modelagem em runtime: o template e o data. Essa é a abordagem mais comum, pois normalmente você cria um modelo e fornece dados dinâmicos mais tarde, quando desejar.

Opção A: dados embutidos

{
    "type": "AdaptiveCard",
    "$data": {
        "employee": {
            "name": "Matt",
            "manager": { "name": "Thomas" },
            "peers": [{
                "name": "Andrew" 
            }, { 
                "name": "Lei"
            }, { 
                "name": "Mary Anne"
            }, { 
                "name": "Adam"
            }]
        }
    },
    "body": [
        {
            "type": "TextBlock",
            "text": "Hi ${employee.name}! Here's a bit about your org..."
        },
        {
            "type": "TextBlock",
            "text": "Your manager is: ${employee.manager.name}"
        },
        {
            "type": "TextBlock",
            "text": "3 of your peers are: ${employee.peers[0].name}, ${employee.peers[1].name}, ${employee.peers[2].name}"
        }
    ]
}

Opção B: Separar o modelo dos dados

Como alternativa, é mais provável que você crie um modelo de cartão reutilizável sem incluir os dados. Esse modelo pode ser armazenado como um arquivo e adicionado ao controle do código-fonte.

EmployeeCardTemplate.json

{
    "type": "AdaptiveCard",
    "body": [
        {
            "type": "TextBlock",
            "text": "Hi ${employee.name}! Here's a bit about your org..."
        },
        {
            "type": "TextBlock",
            "text": "Your manager is: ${employee.manager.name}"
        },
        {
            "type": "TextBlock",
            "text": "3 of your peers are: ${employee.peers[0].name}, ${employee.peers[1].name}, ${employee.peers[2].name}"
        }
    ]
}

Em seguida, carregue-o e forneça os dados em runtime usando os SDKs de modelagem.

Exemplo do JavaScript

Use o pacote adaptivecards-templating.

var template = new ACData.Template({ 
    // EmployeeCardTemplate goes here
});

// Specify data at runtime
var card = template.expand({
    $root: {
        "employee": {
            "name": "Matt",
            "manager": { "name": "Thomas" },
            "peers": [{
                "name": "Andrew" 
            }, { 
                "name": "Lei"
            }, { 
                "name": "Mary Anne"
            }, { 
                "name": "Adam"
            }]
        }
    }
});

// Now you have an AdaptiveCard ready to render!

Compatibilidade do Designer

O Designer de Cartão Adaptável foi atualizado para ser compatível com a modelagem.

Confira em: https://adaptivecards.io/designer

image

  • Editor de Dados de Exemplo – especifique os dados de exemplo aqui para exibir o cartão vinculado a dados quando estiver no "modo de visualização". Há um pequeno botão nesse painel para popular a estrutura de dados com base nos dados de exemplo existentes.
  • Modo de Visualização: pressione o botão de barra de ferramentas para alternar entre a experiência de edição e de visualização de dados de exemplo.
  • Abrir Exemplo: clique neste botão para abrir vários conteúdos de exemplo.

Associação avançada

Escopos de associação

Há algumas palavras-chave reservadas para acessar vários escopos de associação.

{
    "${<property>}": "Implicitly binds to `$data.<property>`",
    "$data": "The current data object",
    "$root": "The root data object. Useful when iterating to escape to parent object",
    "$index": "The current index when iterating"
}

Atribuir um contexto de dados a elementos

Para atribuir um "contexto de dados" a qualquer elemento, adicione um atributo $data ao elemento.

{
    "type": "Container",
    "$data": "${mySubObject}",
    "items": [
        {
            "type": "TextBlock",
            "text": "This TextBlock is now scoped directly to 'mySubObject': ${mySubObjectProperty}"
        },
        {
            "type": "TextBlock",
            "text": "To break-out and access the root data, use: ${$root}"
        }
    ]
}

Repetir itens em uma matriz

  • Se a propriedade $data de um elemento de Cartão Adaptável estiver associada a uma matriz, o próprio elemento será repetido em cada item na matriz.
  • Todas as expressões de associação (${myProperty}) usadas nos valores da propriedade terão um escopo de item individual na matriz.
  • Caso esteja associando uma propriedade a uma matriz de cadeias de caracteres, use ${$data} para acessar o elemento de cadeia de caracteres individual. Por exemplo, "text": "${$data}"

Por exemplo, o TextBlock abaixo será repetido três vezes, uma vez que $data é uma matriz. Observe como a propriedade text está associada à propriedade name de um objeto individual dentro da matriz.

{
    "type": "Container",
    "items": [
        {
            "type": "TextBlock",
            "$data": [
                { "name": "Matt" }, 
                { "name": "David" }, 
                { "name": "Thomas" }
            ],
            "text": "${name}"
        }
    ]
}

Resultando em:

{
    "type": "Container",
    "items": [ 
        {
            "type": "TextBlock",
            "text": "Matt"
        },
        {
            "type": "TextBlock",
            "text": "David"
        }
        {
            "type": "TextBlock",
            "text": "Thomas"
        }
    ]
}

Funções internas

Nenhuma linguagem de modelagem está completa sem um pacote avançado de funções auxiliares. A modelagem de Cartões Adaptáveis é criada com base na AEL (linguagem de expressão adaptável), que é um padrão aberto para declarar expressões que podem ser avaliadas em várias plataformas diferentes. Além disso, é um superconjunto adequado dos "Aplicativos Lógicos" para o uso de uma sintaxe parecida à do Power Automate etc.

Isso é apenas uma pequena amostragem das funções internas.

Confira a lista completa das Funções predefinidas da linguagem de expressão adaptável.

Avaliação condicional

  • if(expression, trueValue, falseValue)

if exemplo

{
    "type": "TextBlock",
    "color": "${if(priceChange >= 0, 'good', 'attention')}"
}

Como analisar JSON

  • json(jsonString): analise uma cadeia de caracteres JSON

json exemplo

Essa é uma resposta do Azure DevOps em que a propriedade message é uma cadeia de caracteres serializada em JSON. Para acessar valores dentro da cadeia de caracteres, é preciso usar a função json no modelo.

Dados

{
    "id": "1291525457129548",
    "status": 4,
    "author": "Matt Hidinger",
    "message": "{\"type\":\"Deployment\",\"buildId\":\"9542982\",\"releaseId\":\"129\",\"buildNumber\":\"20180504.3\",\"releaseName\":\"Release-104\",\"repoProvider\":\"GitHub\"}",
    "start_time": "2018-05-04T18:05:33.3087147Z",
    "end_time": "2018-05-04T18:05:33.3087147Z"
}

Uso

{
    "type": "TextBlock",
    "text": "${json(message).releaseName}"
}

Resultando em

{
    "type": "TextBlock",
    "text": "Release-104"
}

Funções personalizadas

Há suporte para funções personalizadas por meio de APIs nos SDKs de modelagem.

Layout condicional com $when

Para remover um elemento inteiro caso uma condição seja atendida, use a propriedade $when. Se $when for avaliada como false, o elemento não será exibido ao usuário.

{
    "type": "AdaptiveCard",
    "$data": {
        "price": "35"
    },
    "body": [
        {
            "type": "TextBlock",
            "$when": "${price > 30}",
            "text": "This thing is pricy!",
            "color": "attention",
        },
         {
            "type": "TextBlock",
            "$when": "${price <= 30}",
            "text": "Dang, this thing is cheap!",
            "color": "good"
        }
    ]
}

Compor modelos

Atualmente, não há como compor "partes" de modelo juntas. Mas estamos explorando opções que esperamos compartilhar mais em breve. Todas as opiniões são bem-vindas!

Exemplos

Navegue na página de exemplos atualizada para explorar todos os tipos de novos cartões modelo.