Highlight optional and blank page items - Oracle APEX

Indicators like * or labels in bold and red are typically used to indicate mandatory fields in an application. Would it not be nice, as an Oracle APEX developer, to give users of your application the ability to preview optional fields that have not yet been filled out?

A user enters values into 18 fields on an application page with over 20 items but fewer than 5 required fields before saving the entry. The same user wants to check the earlier entries but appears to be unsure of which optional fields need to still be filled in.

Boom! Highlighted items will save the day and the time it would have taken to browse through the entire page.

Demo Link: https://apex.oracle.com/pls/apex/f?p=100471

My Approach

The simple steps below will work on new and existing Oracle APEX application pages

Step 1

In this scenario, I want to highlight all optional and blank page items on a page. therefore I'll create a hidden page item of type SQL Query(return single value) called P10_OPTIONAL_ITEMS to hold all optional page items and also a page item of type switch called P10_TOGGLE_HIGHLIGHT to allow users to toggle and highlight. If you want specific page items please skip creation of page item P10_OPTIONAL_ITEMS.

SQL Query:

select listagg(item_name,',') within group (order by item_name) item_list
from apex_application_page_items
where application_id=:APP_ID
and page_id=:APP_PAGE_ID
and display_as not in ('Hidden')
and is_required = 'No'
and item_name not in ('P10_OPTIONAL_ITEMS','P10_TOGGLE_HIGHLIGHT')

Step 2

Include the following in the section titled "Function and Global Variable Declaration." (highlightItems and UnhighlightItems) are two javascript/jquery functions I've written.
The current page will use this. However, you can write a js file, upload it, and add the File URL if you want it to be used on other pages within the application.
NB: I chose orange for my border and text highlight.

Javascript:

function highlightItems() {
    // set all optional fields on the current page to a variable (you may also explicitly set to the variable)
    var lString = document.getElementById('P10_OPTIONAL_ITEMS').value; //"P10_ITEM1,P10_ITEM2,P10_ITEM3";
    var pString = lString.split(',');
    for (var i = 0; i < lString.length; i++) {
        if (apex.item(pString[i]).getValue().length == 0) {
            //loop through all items 

            var span = document.getElementById(pString[i] + '_error_placeholder');
            var item = document.getElementById(pString[i]);
            // add standard page item error class

            $('#' + pString[i]).addClass('apex-page-item-error');
            $('#' + pString[i] + '_input').addClass('apex-page-item-error');
            var labelText = $('#' + pString[i] + '_LABEL').text()
            // set item border color and include text in error place holder

            item.setAttribute("style", "border-color:orange");
            span.textContent = labelText + ' is blank';
            span.setAttribute("style", "color:orange");
        }
    }
}


function unhighlightItems() {
    // set all optional fields on the current page to a variable (you may also explicitly set to the variable)
    var lString = document.getElementById('P10_OPTIONAL_ITEMS').value; //"P10_ITEM1,P10_ITEM2,P10_ITEM3";
    var pString = lString.split(',');
    for (var i = 0; i < lString.length; i++) {
        // remove standard page item error class and all related attributes
        var span = document.getElementById(pString[i] + '_error_placeholder');
        span.removeAttribute("style", "color:orange");
        $('#' + pString[i] + '.apex-page-item-error').removeClass('apex-page-item-error');
        $('#' + pString[i] + '_input' + '.apex-page-item-error').removeClass('apex-page-item-error');
        var stdelem = document.getElementById(pString[i]);
        stdelem.removeAttribute("style", "border-color:orange");

        if ('textContent' in span) {
            span.textContent = '';
        } else {
            span.innerText = '';

        }
    }

Step 3

If you wish to have a toggle view, include the following dynamic actions. Add DA to item P10_TOGGLE_HIGHLIGHT

On Execute Javascript Code include - highlightItems() when true and unhighlightItems() when false

Step 4

To ensure changes (blank or not null) are tracked on all highlighted page items include Dynamic action. This will suffice for all existing and new items on your page.

Javascript Expression:

document.getElementById('P10_OPTIONAL_ITEMS').value.includes($(this.triggeri

Execute Javascript Code:

if (apex.item('P10_TOGGLE_HIGHLIGHT').getValue() == 'Y') {
    if (apex.item($(this.triggeringElement).prop("id")).getValue().length == 0) {

        var span = document.getElementById($(this.triggeringElement).prop("id") + '_error_placeholder');
        var item = document.getElementById($(this.triggeringElement).prop("id"));

        $('#' + $(this.triggeringElement).prop("id")).addClass('apex-page-item-error');
        $('#' + $(this.triggeringElement).prop("id") + '_input').addClass('apex-page-item-error');
        var labelText = $('#' + $(this.triggeringElement).prop("id") + '_LABEL').text()
        item.setAttribute("style", "border-color:orange");
        span.textContent = labelText + ' is blank';
        span.setAttribute("style", "color:orange");
    } else {
        var span = document.getElementById($(this.triggeringElement).prop("id") + '_error_placeholder');
        span.removeAttribute("style", "color:orange");
        $('#' + $(this.triggeringElement).prop("id") + '.apex-page-item-error').removeClass('apex-page-item-error');
        $('#' + $(this.triggeringElement).prop("id") + '_input' + '.apex-page-item-error').removeClass('apex-page-item-error');
        var stdelem = document.getElementById($(this.triggeringElement).prop("id"));
        stdelem.removeAttribute("style", "border-color:orange");
        span.textContent = '';
    }
}

Conclusion

Continuous improvement on your applications gives better user experience and customer satisfaction. I hope you will find this piece of work helpful.