Posted in JavaScript/jQuery Plugins, Power Apps Portals

Power Apps Portals – JavaScript Tip #02 – Set Attributes Read-Only

Hello and welcome to another JavaScript tip for Power Apps Portals.

In this post I will show you how to set attributes read-only in your Entity Form / Web Form.

A generic way to set an attribute as read-only would be the following:

$("#<attribute name>").attr("readonly", true);

But depending on the datatype of your attribute, some additional changes to the HTML elements might be required. For example, a lookup field is normally rendered with a search button, or a datetime field has the datetime picker next to the input control:

Instead of re-writing the same code every time, let’s create some generic functions passing the field name as parameter, as well as a true/false flag to define if the field should be read-only. We will create a few different functions, according to the field datatype:

Set DateTime ReadOnly

SetDateTimeFieldReadOnly = function (fieldName, readOnly) {
    if (readOnly) {
        $('#' + fieldName).siblings("div.datetimepicker").find("input, .input-group-addon").attr("readonly", true);
        $('#' + fieldName).siblings("div.datetimepicker").find("input, .input-group-addon").css("cursor", "not-allowed");
        $('#' + fieldName).siblings("div.datetimepicker").find("input, .input-group-addon").on("mousedown", function (e) { e.preventDefault(); return false; });
    } else {
        $('#' + fieldName).siblings("div.datetimepicker").find("input, .input-group-addon").attr("readonly", false);
        $('#' + fieldName).siblings("div.datetimepicker").find("input, .input-group-addon").css("cursor", "default");
        $('#' + fieldName).siblings("div.datetimepicker").find("input, .input-group-addon").off("mousedown");
    }
};

Set Lookup ReadOnly

SetLookupFieldReadOnly = function (fieldName, readOnly) {
    if (readOnly) {
        $('#' + fieldName).siblings("div.input-group-btn").find("button").prop("disabled", true);
        $('#' + fieldName).siblings("div.input-group-btn").hide();
    } else {
        $('#' + fieldName).siblings("div.input-group-btn").find("button").prop("disabled", false);
        $('#' + fieldName).siblings("div.input-group-btn").show();
    }
};

Set Checkbox ReadOnly

SetCheckboxFieldReadOnly = function (fieldName, readOnly) {
    if (readOnly) {
        $('#' + fieldName).prop("disabled", true);
    } else {
        $('#' + fieldName).prop("disabled", false);
    }
};

Set Radio Button ReadOnly

SetRadioFieldReadOnly = function (fieldName, readOnly) {
    if (readOnly) {
        $('#' + fieldName).find("input[type='radio']").prop("disabled", true);
    } else {
        $('#' + fieldName).find("input[type='radio']").prop("disabled", false);
    }
};

Set Dropdown ReadOnly

SetDropdownFieldReadOnly = function (fieldName, readOnly) {
    if (readOnly) {
        $('#' + fieldName).attr("readonly", true);
        $('#' + fieldName).css("pointer-events", "none");
    } else {
        $('#' + fieldName).attr("readonly", false);
        $('#' + fieldName).css("pointer-events", "auto");
    }
};

We still need one more function to cater for any other datatype. This will be the main function that we will make the call and we need one additional parameter, representing the field datatype.

This function will validate the field type and call the appropriate function we created above (via switch case), finally having the generic read-only function in the default instruction:

Set Field ReadOnly Function

SetFieldReadOnly = function (fieldName, readOnly, type) {
    try {
        type = type.toLowerCase();

        switch (type) {
            case "date":
            case "time":
            case "datetime":
                SetDateTimeFieldReadOnly(fieldName, readOnly);
                break;
            case "lookup":
                SetLookupFieldReadOnly(fieldName, readOnly);
                break;
            case "checkbox":
                SetCheckboxFieldReadOnly(fieldName, readOnly);
                break;
            case "radio":
                SetRadioFieldReadOnly(fieldName, readOnly);
                break;
            case "dropdown":
                SetDropdownFieldReadOnly(fieldName, readOnly);
                break;
            default:
                if (!!readOnly) {
                    $("#" + fieldName).attr("readonly", true);
                    $("#" + fieldName).css("cursor", "not-allowed");
                    $("#" + fieldName).on("mousedown", function (e) { e.preventDefault(); return false; });
                } else {
                    $("#" + fieldName).attr("readonly", false);
                    $("#" + fieldName).css("cursor", "default");
                    $("#" + fieldName).off("mousedown");
                }
                break;
        }
    }
    catch (err) {
        console.error("Error SetFieldReadOnly: " + err.message);
        return;
    }
};

Now you can combine all JavaScript code above, saving as a .js file (and upload as a Web File), or a Web Template record, or a Content Snippet record, etc. Then refer to it in any Portal page, or even the Tracking Code Content Snippet (so it can be used in every page) – and that’s it, the functions are ready to be used in your Portals.

Posted in JavaScript/jQuery Plugins, Power Apps Portals

Power Apps Portals – Field Label Position

Hi,

In this post I will show you how to set the field label position within an Entity Form/Web Form in Power Apps Portals.

If you are familiar with Dynamics 365, you probably are aware that we can define which position to place a field label within a form. The positions available are:

  • Side: label and input control are positioned side-by-side
  • Top: label and input control are positioned as top-bottom

Unfortunately, Power Apps Portals ignores this definition and always renders your form as top-bottom positioning:

I will show you how to change this behavior to render your field label as side-by-side position. We can achieve this via JavaScript or CSS:

Via JavaScript/jQuery

If you need to set only for a specific form or perhaps specific section in your form, you can use the following jQuery function (just relace the sectionGeneral below for your section name):

$("table[data-name|='sectionGeneral']").find(".control").css("clear", "none");
$("table[data-name|='sectionGeneral']").find(".control").css("float", "right");

Via CSS

If you want to setup this behavior for every Entity Form/Web Form within your Portals, or perhaps for an entire Web Page, you can set it via CSS (you can place this in your .css file or the Web Page custom css field):

.section tbody tr td div.control{
    clear: none !important;
    float: right;
}

Now refresh your Portals Web Page and you will have the below rendered form (don’t forget to clear the cache):

Posted in JavaScript/jQuery Plugins, Power Apps Portals

Power Apps Portals – JavaScript Tip #01 – Hide & Show Elements

Power Apps Portals allows us to add custom JavaScript/jQuery code to manipulate behaviour within the Portals website.

I am starting a series of quick posts with snippets of JavaScript/jQuery code to help you with your Power Apps Portals implementation.

When talking about client-side customization, there is no single way of interacting with the page elements, there are several ways to achieve same results, in this post I will give an example on how to hide & show elements in your page, so here we go:

Hide & Show Fields

$("#<field name>").closest("td").find("div.control, div.info").hide(); // show();

Hide & Show Section

$("table[data-name='<section name>']").parent().hide(); // show();

Hide & Show Tab

$("div[data-name='<tab name>']").prev("h2.tab-title").hide();  // show();
$("div[data-name='<tab name>']").hide();  // show();

Hide & Show Entity List/Sub-grid column

var list = $(".entity-grid")
list.on("loaded", function () {
	list.find("th:contains('<column display name>')").hide(); // show();
	list.find("td[data-th='<column display name>']").hide(); // show();
}); 

Hide & Show Option Set value

$("#<field name> option[value='< option set value>']").hide(); // show();

Do you have any suggestions or requests for another JavaScript tip? Let me know in the comments below.

Posted in JavaScript/jQuery Plugins, Power Apps Portals

Power Apps Portals – Adding field Mask

Currently in Power Apps Portals, we can’t set a mask for a field, which usually improves a lot the UX. In this post I will show you how a simple example to achieve that using JavaScript/jQuery.

In my case, I am adding a whole number field to the Profile page/form.

Download jQuery Mask Plugin

For this example I am using the following jQuery Plugin: https://igorescobar.github.io/jQuery-Mask-Plugin/

  • Download the plugin and locate the jquery.mask.min.js file under the “dist” folder
  • Create a Web File in your CDS environment
    • Note that by default you can’t upload a .JS file, I am going to rename the file to .ES to bypass this validation (you can also change your environment settings but this is not recommended) – but keep the Partial URL as .JS
    • I am going to set the parent page as Home
    • I am going to set it to be hidden from site map and excluded from search
Mask01
Mask02
Mask03

Adding JS library reference

We need to reference the JS, open your Web Page (content page) and add the following to your HTML “copy” field:

Mask05

You can also add the above line to the “Tracking Code” Content Snippet, and this would be loaded in every page, in my example this JS would only be loaded in the Profile Web Page.

Adding the mask via JavaScript / jQuery 

Still in your content page, navigate to the Advanced tab and add the following code:

Mask04
$(document).ready(function () {
       AddWholeNumberMask();
});
AddWholeNumberMask = function()
{
         $("#ollie_wholenumber").mask("00000", { placeholder: "i.e.: 12345" });
};

Result

This is how you will see your mask in the Portal, and the mask will prevent the user from typing non-number fields or more than 5 numbers in my case.

Mask06

You can reference the below documentation for other masks (date field / money / e-mail / etc): https://igorescobar.github.io/jQuery-Mask-Plugin/docs.html

Above I am using a placeholder to indicate the user what the expected format is, but this is optional, I could have the mask just as: $(“#ollie_wholenumber”).mask(“00000”);