In this blog, I will try to explain how to split values in an array and how we concatenate values using Liquid Code.
Wednesday, October 19, 2022
Power Apps Portal - Split and Concatenate Using Liquid Code
Wednesday, October 5, 2022
Coding Standards
C#:
1. Naming Conventions:
a) Pascal Case: Use this style when naming a class, record, or structs. The interface also uses this convention with the prefix of ‘I’. Public members such as fields, properties, events, methods, and local functions also use pascal case.
b) Camel Case: Use this style for method parameters and when naming private or internal fields prefix with ‘_’. If the private or internal field is static us the prefix ‘s_’ instead. If the private or internal field is static thread us the prefix ‘t_’ instead.
2) Layout Convention:
The layout convention is meant to have the code structure in a specific way. Follow these guidelines:
• 4 spaces or a tab is used for indentations
• 1 statement per line
• 1 declaration per line
• Continuation lines require indentations
• 1 empty line between method definitions and property definitions
• Use parentheses to make clauses in an expression apparent
• Region can be used to group separate sections
• Break multiple conditions in an if-statement into several lines instead of one long line
Tip: If you have to scroll in either direction and you remain in the same function or method, it needs to be refactored and broken into smaller parts.
3) Commenting Convention:
Adding comments to the code should provide insights into parts that are not self-explanatory or has a very specific intention not obvious to the reader. Some guidelines to follow for creating comments:
• Comment on a separate line, not in-line
• Begin with a capital letter
• End with a period (.)
• Have a space between the // and the comment
• Don’t created blocks around the comment
All public members require the necessary XML comments and headers, it is also suggested for the rest of the members.
4) Language Guidelines:
String
Use the appropriate string concatenation functions, don’t use ‘+’:
var firstname = $"My name is {user.FirstName}";
Use the StringBuilder class when you need to append strings in a loop or working with large amounts of string.
Var (Implicitly typed)
Use the ‘var’ for local variables when the right-hand side assignment is clear and obvious, or when implicit typing in a loop is used (for-loop).
Don’t use ‘var’ when:
• The assignment is not clear
• The assignment relies on a function
• You can use dynamic for run-time inference
• In a foreach-loop
• You can use the ‘let’ keyword for scope limiting
Note: The keyword ‘var’ needs to be taken up with the programmer on their usage and understanding thereof. Consistency is more important.
5) Array:
This section will provide some notes around the initialization of an array object. When working with arrays, use the concise syntax:
string[] vowels = {"a", "e", "i", "o", "u"};
If you need to specify the array size, or you need to instantiate it, user ‘var’:
var vowels1 = new string[] {"a", "e", "i", "o", "u"};
var vowels2 = new string[5];
6) Delegates:
Use Func<> or Action<> instead of delegate types. Keep to the concise syntax where possible:
public static Action<string> ActionExample1 = x => Console.WriteLine($"x is: {x}");
public static Func<int, int, int> FuncExample2 = (x,y) => x + y;
class DelClass{
public delegate void Del(string message);
public static void DelMethod(string str){
Console.WriteLine("DelMethod argument: {0}", str);
}
}
7) Try-Catch and Using:
The try-catch is used for most of the exception handling. Use the using-statement instead of a try-finally. The using statement can also be used in a shorth-hand version:
using Font font3 = new Font("Arial", 10.0f);
byte charset3 = font3.GdiCharSet;
8) && and ||:
Use the double ampersand (&&) or double pipe character (||) instead of the singles.
9) New:
var instance1 = new ExampleClass();
ExampleClass instance2 = new();
Use the initializers of a class before using the properties:
var instance3 = new ExampleClass { Name = "Desktop", ID = 37414, Location = "Redmomd", Age = 2.3 };
10) Event Handling:
Use the lambda expression when defining an event handler that is permanent:
public Form2()
{
this.Click += (s,e) =>
{
MessageBox.Show(
((MouseEventArgs)e).Location.ToString());
};
}
Else, use the full notation:
public Form1()
{
this.Click += new EventHandler(Form1_Click);
}
void Form1_Click(object? sender, EventArgs e)
{
MessageBox.Show((MouseEventArgs)e).Location.ToString());
}
11) Static Members
Call all the static members by using the class name dot member (ClassName.StaticMethod). Don’t use a derived class name.
12) LINQ
Follow the guidelines on LINQ expressions:
• Use descriptive names for the variables
• Use Pascal casing
• Rename any ambiguous properties that are returned
• Use implicit typing in the declaration
• Use the where-clause before other clauses
• Use multiple from-clauses instead of a join
13) Other Notes
Here are some guidelines on programming in general.
Rule of thumb:
• A function has maximum 50 lines of code
• A class has maximum of 700 lines of code
• Add a space between operators
• Opening and closing parenthesis are present with keywords
• Function and method names should be meaningful
• A function or method has a single responsibility
• Do not hardcode string or number (use a separate file)
• String comparisons are in upper- or lower case
• Use enums instead of strings or numbers where applicable
• Use constants for the logger
• Log messages should be of value
• Maximum number of parameters is 5
• Use a class or structure for more parameters
• Collections should be empty, not null
• Use Any() instead of Count()
• Use foreach instead of for-loop
• Use interfaces instead of concrete classes for collections
• Files and connections should be closed in a finally-statement
• Catch specific exceptions only, not generic ones
• Be careful of swallowing exceptions
Power Apps Portal - Retrieve Data from CRM using Liquid Code only without using FetchXML
Below is the code to retrieve Data from CRM using Liquid Code only without using FetchXML:
{
{% if request.params.id %}
{% assign prd = entities['arp_product'][request.params.id] %} // Get Product Id from URL
{% if prd.arp_productcontactid.id %} // if it has id
{% assign contact = entities['contact'][{{prd.arp_productcontactid.id}}] %} // fetching contact from the contact entity by passing product id
{% assign prcontact = contact.email %} // fetching email from the contact
{% endif %}
{% if prd.arp_rapporteurid.id %}
{% assign contact1 = entities['contact'][{{prd.arp_rapporteurid.id}}] %}
{% assign prrapporter = contact1.email %}
{% endif %}
{% if prd.arp_corapporteurid.id %}
{% assign contact2 = entities['contact'][{{arp.ema_corapporteurid.id}}] %}
{% assign prcorapporter = contact2.email %}
{% endif %}
// Returning these values in the JSON Format
"prodid": "{{request.params.id}}",
"prcontact":"{{prcontact}}",
"prrapporter":"{{prrapporter}}",
"prcorapporter":"{{prcorapporter}}"
{% endif %}
}
Power Apps Portal - Retrieve Data from CRM using FetchXML and Liquid Code
Below is the code for retrieving Data from CRM using FetchXML and Liquid Code:
{% fetchxml products %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="arp_product">
<attribute name="arp_name" />
<attribute name="arp_productid" />
<order attribute="arp_name" descending="false" />
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="arp_parentproduct" operator="eq" value="{{request.params.id}}" />
<condition attribute="arp_producttype" operator="eq" uitype="ema_producttype" value="{xxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" />
</filter>
</entity>
</fetch>
{% endfetchxml %}
{% if products.results.entities.size > 0 %}
{
{%assign size = products.results.entities.size %}
"results":[
{% for product in products.results.entities %}
{
"ProductId": "{{arp.ema_productid}}",
"ProductNo": "{{arp.ema_name}}"
}
{% unless forloop.last %},{% endunless %}
{% endfor %}
],
"length" : "{{size}}"
}
{% else %}
No data found.
{% endif %}
Power Apps Portal - How to write Code for Refreshing Cache Programatically?
As you already know for refreshing the Cache server-side in the Cache, you need to visit <portal_path>/_services/about URL. And you need to press "Clear Cache" for clearing the cache manually. So, that you can see the latest changes made in the CRM.
But Sometimes, there is a need to Refresh Cache Programatically to avoid refreshing it manually. Below is the code which can help you with that:
{% block main %}
{% include 'PortalWebAPIAjax' %}
{% assign urlname = sitemarkers["your site marker name"] %}
{% assign guid = request.params['id'] %}
<script>
function rtc() {
debugger;
try {
var n = Date.now();
var timestamp = n.toString();
var guid = "{{guid}}";
//alert(guid);
webapi.safeAjax({
type: "PATCH",
url: "/_api/entity_logicalname(" + guid + ")/ema_cacherefresh",
contentType: "application/json",
data: JSON.stringify({
"value": timestamp
}),
success: function(res) {
console.log(res);
}
});
} catch (err) {
alert(err.message);
}
}
$(document).ready(function() {
rtc();
//jump to actual detail page
window.location.href = "{{ urlname.url }}?id={{guid}}";
});
</script>
{% endblock %}
Note:
1. The text Highlighted in yellow, needs to get replaced with your component name.
2. Here PortalWebAPIAjax is the separate Web Page for calling Web API. Below is the Code for this web page.
PortalWebAPIAjax :
<script>(function(webapi, $){
function safeAjax(ajaxOptions) {
var deferredAjax = $.Deferred();
shell.getTokenDeferred().done(function (token) {
// add headers for AJAX
if (!ajaxOptions.headers) {
$.extend(ajaxOptions, {
headers: {
"__RequestVerificationToken": token
}
});
} else {
ajaxOptions.headers["__RequestVerificationToken"] = token;
}
$.ajax(ajaxOptions)
.done(function(data, textStatus, jqXHR) {
validateLoginSession(data, textStatus, jqXHR, deferredAjax.resolve);
}).fail(deferredAjax.reject); //AJAX
}).fail(function () {
deferredAjax.rejectWith(this, arguments); // on token failure pass the token AJAX and args
});
return deferredAjax.promise();
}
webapi.safeAjax = safeAjax;
})(window.webapi = window.webapi || {}, jQuery)</script>
Power Apps Portal - What is the Use of Site Markers in the Portal?
You can use site markers in the Portal to avoid using hard-coded values such as titles / Page URLs and you can call it through liquid code.
Below is the Syntax:
For accessing URL: {{ sitemarkers["your marker name"].url }}
For accessing its value as a title etc: {% assign varname = sitemarkers["marker name"] %}
Power Apps Portal - How to Create Custom HTML Table?
You have to create a Web Template for Creating Custom HTML Table through Liquid Code and then you have to link internally with a Page Template and this Page template will be linked to the Web Page. Below is the code. Please check:
{% assign title = 'Page Title Name' %}
{% fetchxml fetchXMLListName%}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="entity_logicalname">
<attribute name="entity_id" />
<attribute name="attribute1" />
<attribute name="attribute2id" />
<attribute name="attribute3" />
<order attribute="attribute1" descending="true" />
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="attribute_filter_field1" operator="eq" uitype="filter_entity" value="{{user.id}}" />
<condition attribute="attribute_filter_field2" operator="eq" uitype="filter_entity2" value="{{request.params.id}}" />
</filter>
<link-entity name="entity_logicalname2" from="entity_id2" to="enity_linkenity"
visible="false" link-type="outer" alias="aliasname1">
<attribute name="attribute1" />
</link-entity>
<link-entity name="entity_logicalname3" from="entity_id3" to="enity_linkenity2" visible="false"
link-type="outer" alias="aliasname2">
<attribute name="attribute1" />
</link-entity>
<link-entity name="entity_logicalname4" from="entity_id4" to="enity_linkenity3" visible="false" link-type="outer"
alias="aliasname3">
<attribute name="attribute1" />
</link-entity>
</entity>
</fetch>
{% endfetchxml %}
<link rel="stylesheet" href="https://cdn.datatables.net/1.12.1/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.5.0.min.js"></script>
<script src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>
<div class="container">
{% block title %}
<h2>{{title}}</h2>
{% endblock %}
<div class="row col-lg-12">
<table class="table" id="myTbl">
<thead class="thead-dark">
<tr>
<th scope="col">Column 1</th>
<th scope="col">Column 2</th>
<th scope="col">Column 3</th>
<th scope="col">Column 4</th>
<th scope="col">Column 5</th>
<th scope="col">Column 6</th>
<th scope="col">Column 7</th>
</tr>
</thead>
<tbody>
{% for result in fetchXMLListName.results.entities %}
<tr>
<td><a href="/url/">{{result.entity_id.name}}</a></td>
<td>
<a href="/url/?id={{result.attribute1}}"
target="_blank">{{result.attribute1}}</a>
</td>
<td>{{ result['aliasname3.attribute1'] }} </td>
<td>{{ result['aliasname2.attribute1'] }} </td>
<td>{{ result['aliasname1.attribute1'] }}</td>
<td>{{ result.attribute2id.name }} </td>
<td>{{ result.attribute3}} </td>
</tr>
{% endfor %}
</tbody>
</table>
<br />
</div>
</div>
<script>
$('#myTbl').DataTable({
"paging": true,
"bPaginate": false,
"bLengthChange": false,
"bFilter": true,
"bInfo": false,
"bAutoWidth": false
});
</script>
Note: Text Highlighted in Yellow, will be replaced with your Title, Entity name, attribute names, link entity names, alias names, filters, table name, etc.
How to Enable Entity to use in the Portal Web API?
You have to first enable your entity to be used in the Portal Web API. For that You need to go to the Portal Management App > Website > Site Settings.
Create Record for New Site Settings. For Web API, You need to create three types of Records i.e. Entity, fields, and error. Please check below:
1. Enable Entity:
Name: Webapi/entity_logicalname/enabled
Value: true
Website: Choose your Website
2) Enable fields (You can select specific fields or type * for all the fields in Value):
Name: Webapi/entity_logicalname/fields
Value: *
Website: Choose your Website
3) Error:
Name: Webapi/error/innererror
Value: true
Website: Choose your Website
Legends:
Text Highlighted in Yellow: You have to write your entity's logical name, the rest will remain as it is.
Text Highlighted in Orange: You have to select your website name.
-
With the more recent versions of the PowerApps Portals, we now have the ability to utilize Portals Web APIs. There are some limitations and...
-
Step 1 : Create New Web Resource (HTML) and below code: <html><head> <title></title> <scrip...