ecLearn LMS, developed by Engineered Code, is proud to sponsor Community Summit North America. Visit us at booth #1857 and get on the list for our Summitland Prize!
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.
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?
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.
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.
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.
[…] post PowerApps Portals: Liquid and JavaScript – Better Together! appeared first on Engineered […]
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.
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
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?
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
Hi Nicholas Hayduk,
I want to read web form step name using Liquid object. Could you please suggest me a better way.
Thanks
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
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
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
Can I assign a variable from javascript to liquid?
eg
var myvalue= $(“#test_field”).val();
{% assign test = myvalue %}
alert(‘{{test}}’);
Unfortunately not. Liquid is executed on the server before it ever gets to the client (which is where JavaScript is rendered).
However, you can use JavaScript to make a call to a Liquid “service” – see Colin’s post on that topic: https://colinvermander.com/2017/04/17/dynamics-365-portals-use-liquid-to-return-json-or-xml/
You can pass parameters on the query string and then leverage them in your Liquid code using request.params.
Nick
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.
Hi Kiran,
Does the out-of-the-box search not meet your needs?
https://docs.microsoft.com/en-us/powerapps/maker/portals/configure/search
If you want to implement a more customized approach, you can use Liquid to query the search index:
https://docs.microsoft.com/en-us/powerapps/maker/portals/liquid/portals-entity-tags#searchindex
Nick
Hi,
I want to implemt search functionality in my webpage. Could you please suggest possible approaches and any references if availalbe.
Thank you
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
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
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.
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
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.
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
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
Users on a portal are contacts, not systemusers. So you can get the contact ID using {{user.contactid}}.
Nick
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
Generally I use Liquid to write out a JSON object, that can then be used in JavaScript.
For example, see Colin Vermander’s post:
https://colinvermander.wordpress.com/2017/04/17/dynamics-365-portals-use-liquid-to-return-json-or-xml/
Nick
Hi, How I can update/delete records using liquid script? What are possible approaches?
Liquid is read-only. To update/delete records, use the Web API.
https://docs.microsoft.com/en-us/power-apps/maker/portals/web-api-overview
Nick
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?
I think this blog post should help:
https://www.engineeredcode.com/blog/inconsistent-behavior-of-liquid-in-the-custom-javascript-attribute-on-entity-lists-in-dynamics-365-portals
Nick
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
If you (rightly) don’t want to expose the URLs and authentication keys, then you’d need a Companion App:
https://learn.microsoft.com/en-us/power-apps/maker/portals/oauth-implicit-grant-flow
https://www.engineeredcode.com/blog/dynamics-365-portal-custom-server-side-code-with-a-companion-app
Nick
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.
This would require custom code. Since the user isn’t logged in yet, you can’t use any information directly from their contact record using Liquid.
One possible way would be to use the new Power Automate integration. You can create a Power Automate cloud flow that, given the invitation code, provided the type of login that you want.
https://learn.microsoft.com/en-us/power-pages/configure/cloud-flow-integration
Nick
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.
Check out this post: https://www.engineeredcode.com/blog/inconsistent-behavior-of-liquid-in-the-custom-javascript-attribute-on-entity-lists-in-dynamics-365-portals
Nick