ENGINEERED CODE BLOG

PowerApps Portals: Knowledge Articles and Liquid

There are some areas of PowerApps Portals that are still implemented using either ASP.NET MVC or ASPX, instead of via Web Templates, which means the configurability options are limited – one of those is the Knowledge Base (which exposes Knowledge Article entities). Often we can use Liquid and JavaScript to customize some of these areas, but there is one thing in particular that makes doing this for the Knowledge Base challenging – in this post I’ll explain what that is, and how to get around it.

The Challenge

First of all, I was inspired by this question on the community forums. The original poster was looking to display custom fields that already exist on the Knowledge Article entity on the Portal (to make things slightly more complicated, he wanted the display to be conditional on the value of another field).

The Knowledge Base is implemented using ASP.NET MVC, which means we don’t have access to customize the part of the code responsible for displaying a Knowledge Article. However, knowing that we can access data from Liquid, and use JavaScript to insert content onto the page (pretty much anywhere we want), means we should be able to accomplish this requirement. Remember, Liquid is a great tool when you want to read/display data.

However, the challenge is getting access to the Knowledge Article that is currently being displayed.

In Liquid, we have access to the global page variable, which tells us which Web Page we are currently viewing. However, because of the way the Knowledge Base is implemented, the page variable will point to the same Web Page, regardless of the Knowledge Article you are looking at (it’s a Web Page called Knowledge Base – Article Details). As far as I know, there is no global variable that will tell you which article you are currently on, similar to how page works.

Now, if we knew the ID of the Knowledge Article, we could get it from the entities global variable. Often you’ll find the ID of the record being viewed in the query string, however for the Knowledge Base, the URL looks something like /knowledgebase/article/KA-01000/en-us. Instead of the ID, the Knowledge Base implementation uses the “article public number” as the unique key in the URL. That won’t help us if we’re trying to use the entities collection.

So what other options do we have?

The Solve

Of course, we have at our disposal what might be the most powerful Liquid tag of all: fetchxml.

Using a FetchXML query, we can look for the article with a particular “article public number”, thus achieving our goal of getting a reference to the article. Once we have that reference, we’ll have access to all of its properties, including any custom attributes.

We first have to do a bit of string parsing, to extract the “article public number” from the URL. Then we can perform our query (we also add a filter on islatestversion, as each version of a Knowledge Article ends up being a separate record in the database). The resulting Liquid looks like:

{% assign urlSplit  = request.path | split: '/' %}
{% assign urlSplitLength  = urlSplit | size %}
{% assign kaCodeIndex = urlSplitLength | minus: 2 %}
{% assign kaCode = urlSplit[kaCodeIndex] %}

{% fetchxml articlefetch %}
    <fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
      <entity name="knowledgearticle">
        <all-attributes /> 
        <filter type="and">
          <condition attribute="islatestversion" operator="eq" value="1" />
          <condition attribute="articlepublicnumber" operator="eq" value="{{kaCode}}" />
        </filter>
      </entity>
    </fetch>
{% endfetchxml %}

{% assign article = articlefetch.results.entities[0] %}

If you read the forum post that inspired this, and may have seen a link to this blog post from Colin Vermander about a technique to customize the entire Knowledge Article display. Part of his solution looks very similar to what I’m describing here (in fact, once I noticed the similarity, I copied his FetchXML statement rather than crafting my own). One difference is that I’m parsing the “article public number” using Liquid, whereas he does his in JavaScript.

The result of this code is you now have the article as a Liquid object, and access to all of its properties.

Displaying the Custom Attribute

The next question, now that we have the Liquid object, how do we display a custom attribute somewhere on the page?

The code that displays the Knowledge Article doesn’t include the “content” of the Knowledge Base – Article Details Web Page anywhere. So anything you put in the Copy attribute won’t be rendered.

The original poster had mentioned perhaps modifying the breadcrumbs Web Template, however the code doesn’t actually use that Web Template – it includes its own custom rendering of the breadcrumbs.

In theory you could put the code in the header or footer, and only display it if the Web Page is Knowledge Base – Article Details. However, most likely that isn’t going to be where you want it.

I think the simplest approach is to add the required markup using JavaScript. While the Copy field of Knowledge Base – Article Details is not rendered, the Custom JavaScript field is. So you can use a combination of JavaScript and Liquid to add your desired markup to the page. Something like:

$(document).ready(function() {
    $('#content').append($('<div>').html('Custom Field: {{article.new_customfield}}'));
});

If you want to conditionally display the field based on some other field on the article, simply wrap that JavaScript in a Liquid if statement. The full code becomes:

{% assign urlSplit  = request.path | split: '/' %}
{% assign urlSplitLength  = urlSplit | size %}
{% assign kaCodeIndex = urlSplitLength | minus: 2 %}
{% assign kaCode = urlSplit[kaCodeIndex] %}

{% fetchxml articlefetch %}
    <fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
      <entity name="knowledgearticle">
        <all-attributes /> 
        <filter type="and">
          <condition attribute="islatestversion" operator="eq" value="1" />
          <condition attribute="articlepublicnumber" operator="eq" value="{{kaCode}}" />
        </filter>
      </entity>
    </fetch>
{% endfetchxml %}

{% assign article = articlefetch.results.entities[0] %}

{% if article.new_customfield2 == 'somevalue' %}

$(document).ready(function() {
    $('#content').append($('<div>').html('Custom Field: {{article.new_customfield}}'));
});

{% endif %}

One drawback to using JavaScript to accomplish this sort of thing is that if you happen to expose your Knowledge Base publicly, the custom field won’t be indexed by search engines. That should be a relatively small concern in most projects.

Leave a Reply

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

Contact

Engineered Code is a web application development firm and Microsoft Partner specializing in web portals backed by Dynamics 365. Led by a professional engineer, our team of technology experts are based in Regina, Saskatchewan, Canada.