Liquid Templates in Dynamics Portals – Part 2

Liquid Templates in Dynamics Portals – Part 1 is a high level overview and a bit of history of Liquid Templates. Now we can take a closer look at Liquid Templates support in Dynamics Portals. While this capability offers flexibility to Portal developers, it can be overwhelming when getting started.

The Microsoft Documentation on Liquid is fairly solid but I think it skips many Liquid fundamentals offered by the Shopify Liquid online documentation. This is understandable since I assume they want to focus on Portals specific extensions, but the foundation is important for newcomers.

In this post, we will cover language features not outlined in the Microsoft Portals documentation:

  • Liquid Templates fundamentals – a quick overview of the main capabilities of Liquid Templates
  • Dynamics specific extensions – what extensions has Microsoft added to Liquid for Portals

Once we cover the fundamentals, we can dig deeper into:

  • Liquid Template usage in Dynamics Portals – where can we use Liquid Templates
  • Common usage patterns – examples of when and how to leverage Liquid Templates in Portals
  • Complex examples – more extensive customization using Liquid

We won’t cover all items in this post but we can get things off to a good start.

Liquid Templates fundamentals

Liquid Templates (or Liquid) is a ‘templating language’ but this phrase can be a bit confusing. When I think of templates, Email templates, Document templates, or even reports come to mind. I see language, I think Java, C#, C++, or Visual Basic with which I can build standalone applications for the desktop, mobile, or the web.

Liquid offers features traditionally associated with templates. With Email or Document Templates in Dynamics 365 CE (CRM), we enter placeholders or slugs for data fields inline with our content. The system fills in the slugs with the selected CRM record data when generating the Email or Document. We can do the same with Liquid and Power Portals – placeholders for Common Data Service (CDS) data that render when the page loads.

Liquid goes beyond templates with capabilities similar to programming languages like JavaScript. For example, you can implement conditional logic using Control Flow operators like the if tag, capture variable values using the assign tag, or we can iterate on collections of items using the loop tag.

So with Liquid, we inject CDS data elements into our Portal content (Templates) and provide some logical control over presentation (Language). These two capabilities make Liquid a powerful means of extending a Portals solution. Let’s take a look at some of the specifics of the Liquid language.

Liquid Template Building Blocks

We know the basics of JavaScript, so what are the basics of Liquid? Right on the Liquid documentation Introduction:

Liquid code can be categorized into objectstags, and filters.

Introduction

I won’t repeat the documentation since it’s well done and pretty extensive. But I think it’s important to understand these three categories:

  • Objects grant access to data and structures from CDS and Portals
  • Tags provide logic and flow to the Liquid Template
  • Filters allow us to process or transform data available in objects

We can access objects using double curly braces. The example below tells Liquid to render the value of the name object:

{{ name }}

Filters extend how we access the object, transforming or processing the data returned with the object. Adding to the example above, we can convert the value of name to upper case with the ucase filter:

{{ name | upcase }}

We access tags using a combination of curly brace and percent sign. Here, we can show some conditional logic using the if tag. This snippet will check to see if the name object is null, and if not, display the text within:

{% if name %}
  Hello {{ name }}!
{% endif %}

Liquid recognizes the elements between the curly braces as our instructions, executes them on the server, and returns the results as our rendered Portal content. This means that objects, tags, and filters are pretty important building blocks for the Liquid Template language!

Liquid Objects and Types

Objects mean data, but what kind of data can we expect? In the standard Liquid documentation, objects have a variety of Types

  • String
  • Number
  • Boolean
  • Nil
  • Array

An object in Liquid can be one of these Types. String, Number, and Boolean should be familiar. Nil is the equivalent of Null and can be important: null values mean something very different than empty strings in CDS. An Array allows working with collections or lists of values, such as a list of strings or numbers. You can iterate on Arrays or access individual items using their position or index.

Right away, we see extensions to the Liquid language by the Power Portals framework. Power Portals supports a few additional Types, as described in the online documentation:

  • Dictionary
  • DateTime

A Dictionary is similar to an Array as it holds collections of values, but items in a Dictionary can be accessed using a string key, not just the index. This will be important when retrieving CDS data. For example, if you have a list of Contacts, you can access a contact by their Id directly:

{{ contact[Id] }}

Also note that an Object can also be a comprised of several of these Types. If we think back to CDS objects, we have Entities with Attributes. For example, a Contact has Attributes like First Name, Last Name, and Created On. An object that represents a Contact and these attributes would then be a combination of String and DateTime types. We could represent these Contact Entity Attributes in Liquid with something similar to the following:

  • {{ contact.firstname }}
  • {{ contact.lastname }}
  • {{ contact.createdon }}

Here we can access a Contact Entity record and Attributes through a Liquid object named contact with String and DateTime properties in a fashion very similar to what we see in JavaScript.

This is another example of CDS extensions to the Liquid language, but standard Liquid objects work in a similar manner. For example, Shopify provides an object called page and from this object, you can access the title like so:

{{ page.title }}

With the basics of accessing data down, how can we work with this data in our Portal?

Operators and Conditional Tags!

Operators allow us to compare or evaluate objects, and the Power Portals support for operators includes a few additions to the Shopify foundation. The standard operators should be familiar to both developers and non-developers alike from math class: Equals (==), Not Equals (!=), Less Than (<), etc.

Operators are used when coupled with conditional logic tags, such as the if tag we have seen in the snippet above. We can update the snippet to use the Equals operator. For example, if we had a Boolean flag indicating whether someone is logged in, we can say hello to the user:

{% if logged_in == true %}
  Hello {{ user.fullname }}!
{% endif %}

More interesting operators worth note are Condition And (and), Condition Or (or). These two operators allow us to check for multiple conditions in one if statement. What if we want to be sure their full name has a value?

{% if logged_in == true and user.fullname != nil %}
  Hello {{ user.fullname }}!
{% endif %}

A few more conditionals that allow us to evaluate strings are contains, startswith, and endswith. We can also check for the page, only showing the Hello message on the Home page:

{% if logged_in == true and user.fullname != nil and page.title startswith 'Home' %}
  Hello {{ user.fullname }}!
{% endif %}

Another conditional tag is unless, which is the opposite of if. We could rework this last snippet using unless:

{% unless page.title startswith 'Profile' %} 
   {% if logged_in == true and user.fullname != nil %}
     Hello {{ user.fullname }}! 
   {% endif %}
{% endunless %} 

Now, we will show the Hello for all pages except their Profile page. This also shows how we can nest these statements. Here, the if conditionals will never be evaluated until the unless conditional is met.

These are simple examples, but we can easily add some conditional logic inline that will be rendered on the server rather than building a lot of JavaScript that needs execute this logic the content on the client.

Filters for transformation

Now we know how to display data using objects and we can decide when to display data using conditional tags, we can transform or manipulate the data using Filters. We add filters to our object display syntax using a pipe “|” delimiter and Filters can be added by platforms extending liquid, but the default filters we get with the base Liquid implementation are pretty extensive.

Many filters offer simple formatting, such as converting the case of a string. Continuing our previous snippet, maybe we want to show how excited we are and make the name upper case by adding | upcase as a filter:

{% unless page.title startswith 'Profile' %} 
   {% if logged_in == true and user.fullname != nil %}
     Hello {{ user.fullname | upcase }}! 
   {% endif %}
{% endunless %} 

Another common example is a format mask for dates. Lets tell the user what day and time it is when they logged into the site:

{% unless page.title startswith 'Profile' %} 
   {% if logged_in == true and user.fullname != nil %}
     Hello {{ user.fullname | upcase }}! Today is {{ "now" | date: "%Y-%m-%d %H:%M" }}.
   {% endif %}
{% endunless %} 

Here we use a special object called now that will return the current date and time, and then we use the date filter that will format the date according to the mask provided. In this example the final result with the date would look something like:

Hello JIM! Today is 2019-08-06 23:24

Liquid provides many other filters for dealing with numbers and collections, such as adding numbers (| plus) or converting . These filters are more useful in more complex situations than just formatting dates or strings. You might be capturing variables while iterating on a loop, or you might be filtering items out of a collection for display on a custom page.

We will dive into some of these more complex filters when we cover collections and additional Portal specific extensions in more detail. We will use some more realistic examples to demonstrate how filters can be extremely useful!

Up next…

This was a fairly long post but we covered objects and data types, conditional tags, operators, and some powerful filters. Understanding these topics are critical because these are used throughout the more complex scenarios offered with Liquid Templates

Next we will take a look at Collections and their related control flow tags in more detail and how they related to more of the Power Portals specific extensions.

As always, comments, questions, and corrections are all welcome!

0 Points


2 thoughts on “Liquid Templates in Dynamics Portals – Part 2”

  1. Ramakanta Behera says:

    both part 1 and part 2 are having same content

    1. Jim Novak says:

      Not sure I understand?

Leave a Reply

Your email address will not be published. Required fields are marked *