Why templating for Adaptive Cards is a game-changer.

Tim Cadenbach
6 min readNov 13, 2019

--

If you never heard of what Adaptive Cards are, it might be a good idea to learn a few things about them before we continue. Also on a separate note, some of the things covered in this post are what we’ve been talking about in the Microsoft Ignite session just recently.

If you prefer watching the session before reading, you can watch the recording here https://myignite.techcommunity.microsoft.com/sessions/81641

Adaptive Cards

Adaptive Cards are platform-agnostic snippets of UI, authored in JSON, that apps and services can openly exchange. When delivered to a specific app, the JSON is transformed into a native UI that automatically adapts to its surroundings. Cards are supported by various Microsoft products but are rendered anywhere you like even in your own apps.

Read more here: www.adaptivecards.io

Adaptive Card Templating

After talking about what Adaptive Cards are, let’s talk about the main topic of this post.

Templating. What is that all about?
Simply explained templating is data-binding onto JSON strings. It’s not even Adaptive Cards related as such it just lets you bind any data, be it JSON formatted or a specific object instance onto your JSON string. Yet similar to what a string replace would do just way more reliable and convenient with support for functions and arrays.

Basic data binding
Within your JSON file you can use placeholders like {person.firstName} or even access multiple levels with like {person.address.streeet} or {person.contact[2].phone}. The templating library is capable of running functions over your data, can repeat JSON structures based on arrays and a few more things.

You can easily access your data using these placeholders to start with:

{
"{<property>}": "Implicitly binds to `$data.<property>`",
"$data": "The current data object",
"$root": "The root data object.",
"$index": "The current index when iterating",
"$host": "Access properties of the host *(not working yet)*"
}

Iterations and Conditions
All this gets even more interesting when we add iterations and conditions to the plate. Let us admit we have the following data returned from any API or database

{
"title": "My list of people:",
"count": 4,
"people": [{
"firstName": "Micky",
"lastName": "Mouse",
"age": 44
},
{
"firstName": "Donald",
"lastName": "Duck",
"age": 12
},
{
"firstName": "Harry",
"lastName": "Potter",
"age": 18
},
{
"firstName": "Matt",
"lastName": "Hidinger",
"age": "28"
}
]
}

Now we want to bind this onto the following JSON template:

{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": "{title}"
},
{
"type": "FactSet",
"facts": [
{
"$data": "{people}",
"$when": "{$index.age > 12}",
"title": "{$index.firstName} {$index.lastName}",
"value": "{$index.age}"
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}

As you can see we access the properties from the data like the title but also firstName and lastName from the people’s array. the $when condition makes sure we only render people who are older than 12.
After transforming the data the resulting JSON will be this:

{
"type": "AdaptiveCard",
"body": [{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": "My list of people"
},
{
"type": "FactSet",
"facts": [{
"title": "Micky Mouse",
"value": "44"
},
{
"title": "Harry Potter",
"value": "18"
},
{
"title": "Matt Hidinger",
"value": "28"
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}

The transformation ignored Donald because his age is not above 12. But it repeatedly added facts for each of the people with condition met.

The final adaptive card would look like this:

Finally transformed and rendered card.

These are just examples, there’s a lot more you can do.
You can find all the available functionality here:
https://docs.microsoft.com/en-us/adaptive-cards/templating/
and
https://docs.microsoft.com/en-us/adaptive-cards/templating/language

Why is that useful now?

Think about how you usually generate JSON to send to any API or how you would normally generate JSON output for your own API. Most likely you have things like classes and serialization in mind, right? While some people already tried different approaches you usually still go with serialization as it was the most convenient way by now. However, generating JSON in your code leads to a couple of issues. It's in your codebase, it has to be compiled, etc. Changes require new releases and you often repeat yourself in various places or apps.

This is especially true when I hear people talk about Adaptive Cards and how they use them. Even some of the Microsoft Examples on how to use the BotFramework for MS Teams say you should do something like this:

// Create card
var card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
{
// Use LINQ to turn the choices into submit actions
Actions = choices.Select(choice => new AdaptiveSubmitAction
{
Title = choice,
Data = choice, // This will be a string
}).ToList<AdaptiveAction>(),
};

Now think about what happens when you want to change anything on your card, add something or even allow someone like your customer to edit this card? Literarily impossible.

With Adaptive Cards Templating data is completely separate from the card layout as such. This means your card template can be anywhere. In your code, in a database or even on a completely remote server fetched by URL.

To render the card you just bind your data onto your template using the template library.

This, for example, is one of the templates we use in our VS Code app: https://templates.adaptivecards.io/teamwork.com/projects/task.json

If you’ve seen code for Adaptive Cards before you should be familiar with it, however, there is no data in it just a lot of placeholders as described above. This template is loaded at runtime when people use our extension.

Adaptive Card rendered in VS Code ( JS / Typescript)

The extension is open-source and available on Github https://github.com/Teamwork/vscode-projects in case you want to have a look at how we did it.

This gives us quite a few interesting options. Let's admit we want to change something in the template, we do not have to do any new release, we don’t do any code changes. We update the template and its changed for all customers using the VSCode extension straight away.

An additional advantage is that you can re-use the same template in various places and can even share it with other people to allow them to use it if you want to. It is just a template, no private data in it.

It's not yet available but we also use the same template in our Visual Studio Pro extension, again the same template from that link above.

Adaptive Card in Visual Studio Pro ( WPF )

Template Repository and sharing templates

I mentioned templates fetched from a remote URL and also “sharing” of templates earlier. Yes, that's becoming a thing with templating.

As templates do not contain any data you can absolutely share the templates with other people. This is especially interesting when talking about common data such as Github issues or weather data, financial reports or data from Microsofts Graph API.
If a template works for one person it surely works for more, if one person invested time to build a template for let's say Github, there may be other people who would use the template for something they work on.

We are working on a Github Integration for one of our Products and we wrote an Adaptive Card template for it. https://templates.adaptivecards.io/github.com/issue_webhook.json

Adaptive Card showing Github Issue within Teamwork Projects ( Knockout / Javascript )

As you might have noticed earlier, the links are all based on https://templates.adaptivecards.io

The developers behind Adaptive Cards have created a proof of concept repository (similar to like npm or docker hub) where anyone can upload templates and make them available. They are working to create a lot of templates for commonly used data like all OData types for MS Graph but also things like flight reports. We added our own templates to that repository to allow anyone who wants to work with Teamwork tasks to use our template. We also shared our Github Template which might get some changes sooner or later.

If you have a template or suggested changes, you can go ahead and add a PR to the repository, it's open-source!

https://github.com/microsoft/adaptivecards-templates

Wrapping things up

In this post, you heard about Adaptive Cards as such, templating and even the template repository. There are a lot more things you can do with these tech pieces but I want to leave that to your imagination for now. I’ll try to cover more topics and examples in more posts later on.

In case you have any questions on all this feel free to reach out here in the comments or on twitter @TimCadenbach

--

--

Tim Cadenbach

Microsoft MVP, Developer Evangelist for DeepL, tech nerd, gamer, husband..loving open source and #AdaptiveCards