Posted in Entity List, Export Content, Power Apps Portals

Power Apps Portals – Generate and Download Word Document from an Entity List

Hi

I recently came across an interesting requirement that I thought would be worth sharing here. Yet again I will be working with Entity Lists, and some implementations will be used from previous posts.

Business Requirement:

  • Display list of records in the Portal
  • Allow users to download a document with record details (including child entities)
  • Document should be (preferably) Word format
  • The document should also be available in D365

Before we dive into the details, here is a sneak peek of what will be achieved by the end of this post:

To achieve this, I will use the following components:

  • Web File with the Word icon
  • Web Page and Entity List for the Contact entity
  • Entity List actions
    • View record details
    • Run Workflow (to generate the Word Document)
  • Entity Permissions
  • Custom entity (Application) with the following relationship:
    • Contact 1:N Application
  • Word Template against the Contact record, displaying contact details and a list of Applications
  • Workflow to set generate Word Template against the Contact record
  • CSS customizations to display my workflow actions as icons
  • JavaScript code to dynamically create the download button

Implementation

My overall approach for this will be using as much as possible existing D365 features, I won’t write any custom code in D365, only client-side code in the Portals will be necessary.

  • Web File:

As I want my Entity List to display a Word Icon, I am creating a Web File and uploading the icon from IconFinder.com

  • Web Page/CSS:

The only customization I am doing around my Web Page is the CSS to display the entity list actions as icons, you can view more details on how to achieve this in the following post: https://oliverrodrigues365.com/2020/05/10/power-apps-portals-adding-icons-to-entity-list-action-buttons-via-css/.

I want to use a Word icon for my “Generate Document” workflow action in my entity list, so I am adding one more class to my CSS, this is to set the height and position of my image (you wouldn’t need this if you were using icons within the bootstrap/glyphicon):

.view-grid .dropdown.action .dropdown-menu .workflow-link .entitylist-icon>img {
    max-height: 18px;
    margin-top: -9px;
}
  • Entity List:

My Entity List is simply pointing to the Active Contacts view, and I am assigning the following Actions against it:

  • Details action redirecting to a new Web Page to display record details
  • Workflow action triggering my custom workflow to generate the document, on the Button Label I am adding my custom CSS class and image:
<span class="fa fa-fw entitylist-icon" aria-hidden="true">
    <img src="icon-word.png"/>
</span>
  • Entity Permissions:

The Word document will be generated as a Note attached to my Contact record in D365, for this reason we need to have an entity permission for the Note entity, this is a child entity permission against my Contact entity permission, for more details on parent/child entity permissions please refer to the following documentation: https://docs.microsoft.com/en-us/powerapps/maker/portals/configure/assign-entity-permissions

  • D365 Application Entity / Contact Entity

I have a custom entity called Application, with some very simple fields for this demo such as ID, Status, Type and Created On.

Another customization I am making is adding a custom field (Text/URL) in my OOB Contact entity to store the URL of my document, I am calling this “Generated Document URL”.

Finally make sure this URL field is available in your view being displayed on the Portal, in my case the Active Contacts view. Don’t worry, we will hide the column via JavaScript, but this will be important on a later stage.

  • Word Template

I am using the OOB Word Template feature to generate my document. What I like about this is that we can generate the document manually via D365 or through a workflow, which is perfect for my scenario. For more details on how to create the Word Template please refer to the following: https://docs.microsoft.com/en-us/power-platform/admin/using-word-templates-dynamics-365.

My template will display a logo image, the Contact name and e-mail and a list of the existing Applications.

  • Workflows

We need two sync workflows to achieve our need. Here I will describe each of the workflow steps:

Generate Word Document
Sync Workflow
Trigger: On-Demand
Entity: Contact
Scope: Organization
Steps: 
 - Perform Action: SetWordTemplate (pass the contact record and set the Word Template created as actions parameters)

The SetWordTemplate is an OOB action that creates a note against the record with the generated Word Document.

A note record in your Portal can be accessed via the following URL pattern: <portalurl>/_entity/annotation/<note guid>, so now we need to generate the URL against the Contact record. For this I am creating the below workflow:

Set Contact Generated Document URL
Sync Workflow
Trigger: Record is created
Entity: Note
Scope: Organization
Steps: 
 - Validate if the Regarding field of the note is a Contact
 - Validate if the File Name is <your word template name> (you can make better validations, I am going for simple ones for this demo)
 - Now we need the note GUID, to avoid code I am using the D365 Workflow Tools solution: https://github.com/demianrasko/Dynamics-365-Workflow-Tools/blob/master/docs/GetRecordID.md but you could also write your own custom code to retrieve the record GUID
 - The next step is to update the related Contact record with the URL pattern + Note GUID. All we need here is the relative path, no need for the Portal root URL (as this might change between environments or other reasons)
  • Entity List JavaScript:

At this point we have the core of our development done. If you navigate to your Web Page you should have the Word icon to generate your document, and once triggered, the URL column from your view, once empty, should get populated with the document URL, if you click that URL you should be able to download your document.

Now we need to add a JavaScript logic, attached to the Entity List Load event, that will perform the following actions:

  • Hide URL column
  • For each row:
    • Get the URL from the “Generated Document URL” attribute
    • If this contains data, create dynamically an element in the same structure as the other elements
    • Append new element to the workflow links so it will be the last action

The following JavaScript code can be placed in the Entity List custom JavaScript section:

$(document).ready(function() {
    SetDownloadButton();
});

SetDownloadButton = function() {

    var entityList = $(".entitylist.entity-grid").eq(0);

    entityList.on("loaded", function() {

        // hide url column 
        entityList.find("table thead th").eq(4).hide();
        entityList.find("table tbody tr").each(function() { $(this).find("td").eq(4).hide(); });

        entityList.find("table tbody > tr").each(function(index, value) {
            var tr = $(this);

            var documentUrlAttribute = tr.find('td[data-attribute="ollie_generateddocumenturl"]');

            if (documentUrlAttribute.length > 0) {
                
                var documentUrl = $(documentUrlAttribute).attr("data-value");

                var downloadElement = "";
                downloadElement += "<li>";
                downloadElement += "    <a href='" + documentUrl + "' target='_blank'>"
                downloadElement += "        <span class='fa fa-download fa-fw' aria-hidden='true'/>";
                downloadElement += "    </a>";
                downloadElement += "</li>";

                var generateWord = tr.find(".dropdown-menu");
                generateWord.append(downloadElement);
            }
        });
    });
};

Now after refreshing the cache and your Web Page you should see the below behavior:

  • Caching Issues?

We all know the Portals have some caching issues, but this shouldn’t be an issue with the above implementation. For any actions triggered by the Portals, the cache is automatically refreshed for that record, as in our scenario we are using sync workflows, the cache gets refreshed within the same transaction.

Conclusion

My example was specific to generate a Word document using a Word Template in D365, but this approach could be used for several other requirements where you have a workflow updating the main record in real-time, and appending a dynamic link to anything on your entity list.

Have you ever had a similar requirement? Please comment below with how you implemented it.

If you find this post useful feel free to like and share it.

Posted in Export Content, Power Apps Portals

Power Apps Portals – Print/Export Content

Power Apps Portals provides us with very quick and simple ways to expose data from the D365 system into an external portal. Often, we have requirements to export or print the data using current Word Templates present in D365, but unfortunately there is no OOB feature (currently) for performing this task.

In this post, I will describe what is available using the OOB configuration from the portal, and how to extend it in order to export the data in the application. The idea of this post is not explain the Portal objects (Web Template,  Entity List etc), you can find content on the Power Apps Portals on the following link: https://docs.microsoft.com/en-us/dynamics365/portals/configure-portal

For this demo, we will be using the following setup:

  • Power Apps Portals Starter (Version 9.2.2.15)

Before going to the step-by-step, below you can see what we will be achieving by going through the end of the post:

PrintPage

As a starting point, we will create an Entity List and Web Page record to present a list of the Active Contacts:

This is how the list will be rendered by default in your Portal page:

Capture02

For Entity List records, we have the option (OOB) to add an Export to Excel button, this can be achieved by:

  • Open your Entity List record
  • Navigate to tab Options
  • In the Grid Configuration add a “Download” action and add a label
Capture03

This is how the button is shown on the Portal, and once clicked, you will download an Excel file with the list content:

Capture04
Capture05

Unfortunately, this excel file is rendered just like our Advanced Find Export to Excel feature, which is not bad, but usually when we have a Website, we (and our customers) want this information to be presented in a friendlier way.

So now, we are going to the fun part, let’s extend this by creating our custom “Print Button”, which will use the standard JavaScript function to print a Page.

Now create a new Page Template and Web Template and make sure to associate the new Page Template to your existing Web Page:

Capture06
Capture07

For the Web Template record, I basically copied the content from the OOB Web Template “Full Page” and removed a few lines, leaving only the condition that will render the Entity List.

At this moment, nothing has changed and our Web Page is behaving exactly the same way as before.

Now, we are going back to our recently created Web Template, and add the following:

  • Give a name for the Div that is holding your Entity List
  • Add the Button for printing (outside the div)
  • Add the JavaScript code that will actually perform the printing (in the .JS code, I am actually creating a new HTML document, so we need to reference the .css here)

What I am also going to do, is add a new hidden DIV in the page with a custom logo (just create a Web File and upload your Logo in the notes), we can play around with showing/hiding the DIVs as we want in the JavaScript function, just make sure to set it up back to normal before the user closes the print window.

  • Add DIV with logo inside your print DIV
  • Show the Logo before setting the HTML content, also hide the Command Bar which will contain your Search Box / View Selector / Create or Download button (in case you setup any of those)
  • After setting the HTML Content, Hide the Logo and show again the Command Bar
  • In the top of the HTML, before the <head>, add:

Now we have our Logo being shown only for the printed window, and we have the same layout as the Portal webpage.

The following is the final code for the Web Template:

{% extends 'Layout 1 Column' %} {% block main %} {% include 'Page Copy' %} {% if page.adx_entitylist %}
<div id="printList">
    <div id="dvLogo" style="text-align:center; display:none">
        <img style="width: 300px;" src="/company-logo.png">
    </div>
    {% include 'entity_list' key: page.adx_entitylist.id %}
</div>
<form id="printForm">
    <input class="entitylist-download btn btn-info action" type="button" value="Print Contacts" id="btnPrint" />
</form>
{% endif %}
http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
<script type="text/javascript">
    $("#btnPrint").on("click", function() {
        document.getElementById('dvLogo').style.display = 'block';
        document.getElementsByClassName("view-toolbar grid-actions clearfix")[0].style.display = 'none';

        var divContents = $("#printList").html();

        document.getElementsByClassName("view-toolbar grid-actions clearfix")[0].style.display = 'block';
        document.getElementById('dvLogo').style.display = 'none';

        var printWindow = window.open('', '', 'height=600,width=800');
        printWindow.document.write('<link rel="stylesheet" href="/bootstrap.min.css" />');
        printWindow.document.write('<html><head><title> Active Contacts</title>');
        printWindow.document.write('</head><body>');
        printWindow.document.write(divContents);
        printWindow.document.write('</body></html>');
        printWindow.document.close();
        printWindow.print();
    });
</script>
{% endblock %}

Conclusion

You can also use the same implementation to any other Web Page in your Portal, this way you can, for example, create a custom Web Template for your entity, displaying the information the way you need and add the Print button, showing and hiding anything on the Web Page if required, like logos, sensitive information, etc.

Maybe in the future Microsoft provides us a way to export using Word or Excel templates, which would be a very nice feature.

I hope this post has been helpful to you and your Power Apps Portals implementation.