ecLearn - Learning Management System built on top of Microsoft Dataverse for Power Platform and Dynamics 365 users

ENGINEERED CODE BLOG

PowerApps Portals: Liquid and JavaScript – Better Together!

PowerApps Portals offers two primary languages for customization: JavaScript and Liquid. This leads to confusion as to which technology should be used, and when – I’ll try to clear up some of that confusion in this blog post, as well as demonstrate that in many cases the best option is a combination of the two.

And before anyone comments, yes I know you can use C# in plugins, and virtually any language with something like a Companion App, but the main go-to languages for PowerApps Portals development are Liquid and JavaScript.

Server-side vs Client-side

The first thing to understand is that Liquid is a server-side language and JavaScript is a client-side language.

Server-side languages are executed by the server, and the browser only sees the results of its execution. On the other hand, the full source code for client-side languages are sent to the browser in plain text, meaning anyone can see what’s going on.

This means that if you are working with data that is sensitive, you might want to consider doing as much as possible in Liquid. For example, let’s say you are building an events registration system, and you only want users to be able to register if the event hasn’t hit capacity. However, you’d prefer not to share with everyone how many people are currently registered, or what the limit is. You can pull the data and perform a calculation to determine if a user can register, all within Liquid – all the user sees is the end result of the calculation, not how it was calculated.

On the other hand, JavaScript is a more sophisticated language which allows for more complex calculations. For example, the number of available math operations in JavaScript is higher than Liquid.

JavaScript also allows you to modify the DOM. While Microsoft is moving towards implementing much of the functionality in Liquid using Web Templates (which means it can be modified by Portal administrators), there is still a lot of functionality where customization is limited to what you can do in JavaScript.

Another consideration is performance. If your complex calculation can be done in either JavaScript or Liquid, would you prefer to offload that to the client’s machine, or do you want it done on the server?

Accessing CDS Data and Authentication

The primary way of accessing CDS (aka Dynamics) data is using Liquid – there are no out-of-the-box APIs offered by the Portal that are easily consumable in JavaScript (yet). Therefore, if you are wanting to read data, Liquid is your best friend, using techniques like the entities global object and the fetchxml tag.

Similar to accessing CDS data, Liquid is the best way to determine if the user is logged in, and if so, who they are.

Better Together

Since both technologies have their advantages, I find that often the best approach is to use both. That is, use Liquid to generate dynamic JavaScript.

Let’s say on your Open a New Case form, you wanted to customize the heading on the page to instead say “Open a New Case for [Contact Name]”. We need to use JavaScript to modify the DOM, but we need to use Liquid to get name of the current user. The JavaScript to accomplish this looks something like:

$(document).ready(function() {
	$('.page-header h1').html($('.page-header h1').html() + ' for {{user.fullname}}');
});

If you’re new to this sort of thing, the biggest challenge is thinking about what gets evaluated when. Many first timers might do something like this instead:

$(document).ready(function() {
	$('.page-header h1').html($('.page-header h1').html() + ' for ' + {{user.fullname}});
});

Notice that I’m using {{user.fullname}} like a variable, which may seem more natural. However, you need to remember that Liquid is evaluated on the server, and then sent to the browser. The browser sees the output of the Liquid code. So the browser actually would see:

$(document).ready(function() {
	$('.page-header h1').html($('.page-header h1').html() + ' for ' + Nicholas Hayduk);
});

The above code contains syntax errors. Instead, if we go back to the original snippet of code, it would output the following:

$(document).ready(function() {
	$('.page-header h1').html($('.page-header h1').html() + ' for Nicholas Hayduk');
});

That is syntactically correct JavaScript.

One trick that might keep this straighter is to declare a variable, and initialize it to a value using Liquid, like so:

$(document).ready(function() {
	var name = '{{user.fullname}}';
	$('.page-header h1').html($('.page-header h1').html() + ' for ' + name);
});

Again, a common mistake when using that technique is to not wrap the Liquid in quotes, which produces incorrect syntax.

Using this technique, you can get quite sophisticated. One technique I use a lot is to use the fetchxml Liquid tag to get a list of entities, then I use a Liquid for loop to output a JavaScript array. Fellow Business Applications MVP Colin Vermander provides a great example in his blog post on Dynamics 365 portals: Use liquid to return JSON or XML.

Caution: there are certain situations when Liquid in the Custom JavaScript on Entity Lists will not get evaluated. See this blog post for more information.

Liquid Debugging

Debugging Liquid code is a question that has come up multiple times on the Microsoft Dynamics Community forums (as examples, there is this thread and this thread).

Unfortunately there is no simple answer. Since it runs server-side, and we don’t have access to the servers that Microsoft uses to host the Portal, we can’t step through Liquid code. Instead, we have to rely on insert logging messages into our Liquid code. But again, since we don’t have access to the server, where should we log to? This is where JavaScript helps us out.

By inserting console.log() or alert() statements throughout our Liquid code, we can get more details on what’s happening. Remember to wrap your console.log or alert statement in script tags if your Liquid isn’t in a Custom JavaScript attribute.

Building on the example from above, I can do something like:

$(document).ready(function() {
	var name = '{{user.fullname}}';
	console.log('{{user.fullname}}');
	console.log('{{user.firstname}}');
	console.log('{{user.lastname}}');
	$('.page-header h1').html($('.page-header h1').html() + ' for ' + name);
});

Again, don’t forget to wrap your Liquid code in quotes, as typically you want to pass strings to console.log or alert.

34 responses to “PowerApps Portals: Liquid and JavaScript – Better Together!”

  1. […] post PowerApps Portals: Liquid and JavaScript – Better Together! appeared first on Engineered […]

  2. Serge van den Oever says:

    Can you explain how to include JavaScript or link to a JavaScript file in PowerApps Portals, seems to be possible from within a form, but would like to do it outside a form, and for example be able to include ReactJS and custom code.

    • Nicholas Hayduk says:

      Hi Serge,

      You’ve got a few options.

      For external library hosted on CDN, you can include references directly to them using script tags.
      Or, you can upload them as web files, and then reference their URL in script tags.
      Or, you can include the JavaScript in a web template, and include the Web Template on the page using the Liquid include tag.

      For larger libraries, the last option is less desirable, because you won’t be taking advantage of the caching of JS files.

      Now, the next step is to figure where to include your

  3. Ankit Shah says:

    PowerApp Portal queries :

    > I’ve a SUBMIT button on the web page. I wish to display other fields on the underneath the SUBMIT button on the same web page on click of SUBMIT. Can anyone advise how we can achieve this?

    > There is one Contact field on the web page, I wish to filter this field. This should be filtered and displayed the associated contacts of the logged in contact’s company. How can I achieve this?

    > How can I get logged in contact’s geolocations, latitude and longitude values?

    > How can I get an embedded view on Google Maps on PowerApp Portal web page?

    Could you advice how to achieve the above tasks in PowerApp Portal?

    • Nicholas Hayduk says:

      Hi Ankit,

      Are the fields you want to put after the submit button read only? If yes, you could build out a Web Template that includes the Entity Form and then use Liquid to display additional text below it. If you are wanting them to be editable fields, you’ll need to use JavaScript to move the fields around.

      For the Contact field, lookups respect the setting that you configure on your form – so you can select a specific view to be displayed. If your Entity Permissions allow users to only see associated contacts, then security trimming will do what you need. If users can see more contacts, but in just this particular case you want to limit to their own company’s contact, you can take advantage of the fact that when you define a view that references a specific Account, that account will get replaced with the user’s account automatically. So you’d need to create a view that displays contact related to a specific account (doesn’t matter which one you pick, as it will get replaced by the current user’s account). The same thing applies when you have a view that references a specific contact – it will get replaced by the current user’s contact.

      To get the current user’s geolocation, you’ll need to use the JavaScript geolocation APIs.

      To add Google Maps on a Power Apps Portal, you’ll need to use JavaScript (using either the Google Maps APIs, or embed codes).

      Hope that helps.

      Nick

  4. Rey says:

    Hi Nicholas Hayduk,

    I want to read web form step name using Liquid object. Could you please suggest me a better way.

    Thanks

    • Nicholas Hayduk says:

      Sorry, I don’t know an easy way of getting the current step in Liquid.

      You might be able to come up with a way by looking at the start step of the web form step of the current page (for when the step isn’t in the query string), and using the ID from the query string on all other pages, but that means enabling Entity Permissions for Web Forms and Web Form Steps.

      Can you tell me why you need the step name in Liquid?

      Nick

  5. Rey says:

    I want to send data to some third party tool on the page load.
    I am not sure how to get it. I have tried jquery as well but didn’t got any way, So I thought I can get through liquid.
    You can suggest if you have something to get web step name using jquery.

    Thanks
    Rey

    • Nicholas Hayduk says:

      Are you using the progress indicator to show the step names on the page? If so, you can use JS to find the step with the “current” class. If not, you can turn that on, use CSS to hide it, and then use the same technique.

      Nick

  6. lawix says:

    Can I assign a variable from javascript to liquid?
    eg
    var myvalue= $(“#test_field”).val();
    {% assign test = myvalue %}
    alert(‘{{test}}’);

  7. Kiran T says:

    Hi,

    I want to integrate serach functionality in portal page. When user types search keyword I want fetch matching entity records and show on the page. Could you please suggest the approach and any reference blogs.

    Thank you.

  8. Kiran T says:

    Hi,

    I want to implemt search functionality in my webpage. Could you please suggest possible approaches and any references if availalbe.

    Thank you

  9. Matias says:

    Hello Noicholas, greetings from Chile…

    I’m new to portals.. Powerapps Portals…. do you have any suggestions on passing via Liquid the “current user email” as a parameter to an ASP.Net application that is going to be added to the portal via iframe capacity?

    The thing is this ASPNET application needs to know “who” is connected in order to filter the data for that particular user…. any hint would be highly appreciated

    Best Regards

    • Nicholas Hayduk says:

      Hi Matias,

      The quickest/easiest way to do this is to include a query string parameter in your iframe URL – something like:

      The problem with this is that it is not secure – anyone can inspect the page, see the URL, and change the email address.

      What authentication mechanism are you using on your portal? To achieve “real” single sign-on, I’d recommend using the same identity provider for both sites, so that what you login to the portal, you’d also be logging into the ASP.NET application, and then the ASP.NET application knows who is logged in without having to pass it via the iframe. For example, you could use Azure AD B2C for both the portal and your ASP.NET application.

      Nick

  10. Mittal says:

    Hi Nick,

    I’ve implemented an Entity Form with various JavaScript validations. Now, when JavaScript is disabled on client browser, many things stopped working on Entity form Web Page. Hence, I decided to use liquid, but still not able to make a way to implement all of those validations. For example, on entity form I have a date of birth field and OnChange event I want to calculate Age and display in next field. How can I achieve this using liquid + javascript?

    Thank you.

    • Nicholas Hayduk says:

      Liquid is a server-side templating (read-only) language that won’t really help you with validation.

      If you are concerned about JavaScript being disabled on the browser, the only protection I can think of is to write synchronous plugins or workflows that perform the validation that can stop the record before it is saved. But I would do this in addition to JavaScript, not instead of.

      Nick

  11. DJ says:

    longshot, but here goes….

    How do I get the case number into the success message for Create Case?

    I have the entity form created and all of the portal artifacts. It works I can create cases.

    However, I would like to inform the user of the case number upon success.

    • Nicholas Hayduk says:

      Great question – I might do a video for this!

      In the meantime, if you redirect to another page on success, you can configure it so that the ID of the newly created record is in the query string. With that ID, you can use Liquid to get the Case Number.

      Nick

  12. Sagar Konda says:

    Hi I want to get current logged in user id (systemuser.id) in Power portal how can i achieve this?
    I tried this code
    $(document).ready(function() {
    var userid= ‘{{user.systemuserid}}’;
    $(‘.page-header h1’).html($(‘.page-header h1’).html() + ‘ for ‘ + userid);
    });

    but this returns blank

    • Nicholas Hayduk says:

      Users on a portal are contacts, not systemusers. So you can get the contact ID using {{user.contactid}}.

      Nick

  13. Hi, How can I get the liquid fetched data using fetchxml tag into javascript? either into webtemplate script tag or into webpage on load script?

    Currently I have implement is ‘Get the current login contact’ into script tag

  14. Sapna Dhage says:

    Hi, How I can update/delete records using liquid script? What are possible approaches?

  15. Anon1 says:

    Hi Nicholas,

    I’m using the method to acquire the contactid on an basic form (custom javascript tab) and it works fine.
    var contactId = “{{ user.contactid }}”;
    console.log(contactId );
    returns
    “feca4615-5a96-46ae-b819-9fa21be3168e”

    However, when I’m using the exact same syntax on custom javascript on an entity list, the server does not translate the liquid syntax. Instead, I get:
    var contactId = “{{ user.contactid }}”;
    console.log(contactId );
    returns
    “{{ user.contactid }}”

    Do you have any idea why this is occuring, and ways to circumvent this?

  16. bssienes says:

    I want to call a 3rd part API and display the retrieved data on a Power Page. How can I do that? I don’t want to expose the API URL and authentication keys in the page sources.

    Please help!

    Thanks

  17. Jaydip patil says:

    How can I access contact custom fields values on portal registration page before register.
    When I hit the invite link,it will show invite code and register button. After it will show registration page on same page i have local and b2c registration option. Based on custom field value i want to hide either of registration method controls.

  18. Sajeda Sultana says:

    Hi Anon1,

    I’m using the method to acquire the contactid on an basic form (custom javascript tab) and it works fine.
    var contactId = “{{ user.contactid }}”;
    console.log(contactId );
    returns
    “feca4615-5a96-46ae-b819-9fa21be3168e”

    However, when I’m using the exact same syntax on custom javascript on an entity list, the server does not translate the liquid syntax. Instead, I get:
    var contactId = “{{ user.contactid }}”;
    console.log(contactId );
    returns
    “{{ user.contactid }}”

    I am facing same problem. Have you solved the issues? Please help.

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 & Power Platform. Led by a professional engineer, our team of technology experts are based in Regina, Saskatchewan, Canada.