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.