Some PDIs are currently unavailable, and PDI actions are paused. View the latest updates here. Read More

Dynamic clickable Knowledge Articles in Record Producer based on dependent variable selection

manishkrpal
Tera Contributor

 

I have an HR Record Producer with two dependent choice variables:

  • Q1 - Help Area (7 choices)
  • Q2 - Details (28 dependent choices based on Q1)

When the user selects a value in Q2, I want to display a box below the field containing 4-5 related Knowledge Articles.

The box should display something like:

 

 
Related Knowledge Articles

• KA0012345 - How to Update Bank Details
• KA0015678 - Payroll FAQ
• KA0019876 - Tax Declaration Process
• KA0014321 - Salary Slip Guide
 

Each KA Number and Title should be clickable, and clicking it should open the Knowledge Article in a new page/tab.
I already created a custom mapping table containing with Q1 ,Q2 ,Country,KA number,KA Title

What I Tried

Option 1 - Custom Variable (Widget)

I created a Custom Variable and added a widget to dynamically display the Knowledge Articles.

Unfortunately, the widget does not render inside the Record Producer in Employee Center/Service Portal. I found that widgets/UI Macros have limitations depending on the portal implementation.

Option 2 - Rich Text Label

Now I'm considering using a Rich Text Label variable and dynamically updating its HTML through a Catalog Client Script or GlideAjax.

I am not sure whether this is the recommended approach or if there is a better OOTB solution.

My Questions

  1. What is the recommended approach for dynamically displaying multiple clickable Knowledge Articles inside a Record Producer in Employee Center Pro?
  2. Can a Rich Text Label be updated dynamically using HTML after the user changes the Q2 value?
  3. Is there any supported OOTB component or widget that can display dynamic Knowledge Article links inside a Record Producer?

    Each article should be clickable and open the corresponding Knowledge Article.

    The solution must work in Employee Center Pro / Service Portal for a Record Producer.

    If anyone has implemented something similar or can suggest the best practice, sample implementation, or architecture, I would really appreciate your guidance.

    Thank you!



1 REPLY 1

Shruti
Giga Sage

The best practice  is to leverage Contextual Search or AI Search Assist, which can proactively surface relevant Knowledge Articles based on the user's inputs . Please refer to OOTB "Create Incident" record producer.

However, since you already maintain a custom mapping table that links specific Help Area (Q1) and Details (Q2) values to Knowledge Articles a practical and straightforward solution is to use an HTML variable to display the mapped articles.

 

  1. Create an HTML variable on the Record Producer (mark it as Read Only).
  2. Create an onChange Catalog Client Script on the Details (Q2) variable.
  3. In the client script, call a GlideAjax Script Include and pass the selected Q1/Q2 values.
  4. The Script Include queries your mapping table and returns the matching KB article numbers and titles.
  5. Build the HTML dynamically and populate the HTML variable using g_form.setValue().
  6. Render each article as a clickable link that opens the Knowledge Article in a new tab/window.

 

Sample client script

Onchange client script on q2 variable

 

function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue === '') {
        g_form.setValue('related_knowledge_articles', '');
        g_form.setDisplay('related_knowledge_articles', false);
        return;
    }


    var ga = new GlideAjax('<ScriptIncludeName>'); // replace with script include name
    ga.addParam('sysparm_name', '<functionName>'); // replace function name
    ga.addParam('sysparm_q2', newValue);
    ga.getXMLAnswer(function(response) {
        if (!response) return;

        try {
            var articles = JSON.parse(response);

            if (articles && articles.length > 0) {

                var isPortal = false;

                try {

                    var targetLocation = (typeof top !== 'undefined' && top.location) ? top.location : window.location;
                    var urlParams = new URLSearchParams(targetLocation.search);

                    if (urlParams.has('id')) {
                        isPortal = true;
                    }
                } catch (err) {
                    isPortal = false;
                }

                //  Build the HTML Box
                var html = '<div style="border: 1px solid #ddd; border-radius: 4px; padding: 15px; background-color: #f9f9f9; margin-top: 10px;">';
                html += '<strong style="font-size: 14px; color: #333;">Related Knowledge Articles</strong>';
                html += '<ul style="list-style-type: disc; margin-top: 10px; padding-left: 20px;">';

                for (var i = 0; i < articles.length; i++) {
                    var articleUrl = '';

                    if (isPortal) {
                        // Relative path maintains current portal prefix (/esc or /sp) seamlessly
                        articleUrl = '?id=kb_article_view&sysparm_article=' + articles[i].number;
                    } else {
                        // Native backend view link structure
                        articleUrl = '/kb_view.do?sysparm_article=' + articles[i].number;
                    }

                    html += '<li style="margin-bottom: 8px;">';
                    html += '<a href="' + articleUrl + '" target="_blank" style="color: #2780e3; text-decoration: underline; font-weight: bold;">';
                    html += articles[i].number + ' - ' + articles[i].title;
                    html += '</a>';
                    html += '</li>';
                }

                html += '</ul></div>';

                //  show HTML variable
                g_form.setValue('related_knowledge_articles', html);
                g_form.setDisplay('related_knowledge_articles', true);

            } else {
                g_form.setValue('related_knowledge_articles', '');  //HTML variable
                g_form.setDisplay('related_knowledge_articles', false);
            }
        } catch (e) {
            console.error("Error parsing articles JSON: " + e);
        }
    });
}
 
 
Sample Script include function
getArticles: function() {
        var q2 = this.getParameter('sysparm_q2');
       
        var articles = [];
       
        if (query !== '') {
            var mappingRec = new GlideRecord('<MappingTable>'); // replace mapping table
            mappingRec.addQuery('articles',q2); // replace query as per table fields
            mappingRec.query();

            while (mappingRec.next()) {
                articles.push({
                    number: mappingRec.getValue('number'),
                    title: mappingRec.getValue('short_description'),
                    sys_id: mappingRec.getValue('sys_id')
                });
            }
        }

        return JSON.stringify(articles);
    },