Message in Service Portal There is a JavaScript error in your browser console

cj10121
Tera Contributor

Goal is to autopopulate client to a form after dob and telephone numberis verifed. On save the form will show 3 buttons Create appt, product complaint, service complaint This works fine. When the 3 buttons show and I select create appt. it ports to the service portal well but I receive the message there is an error in my browser
I will provide the script include, client script and  catalog client script for the appt. booking below

var ClientLookup = Class.create();
ClientLookup.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {

    getClientByDobAndPhone: function() {

        var dob = this.getParameter('sysparm_dob');
        var phone = this.getParameter('sysparm_phone');

        if (!dob || !phone) {
            return JSON.stringify({
                found: false
            });
        }

        var gr = new GlideRecordSecure('x_1817858_ske_skinenvy_client_roster');
        gr.addQuery('d_o_b', dob);
        gr.addQuery('phone_number', phone);
        gr.query();

        if (gr.next()) {
            return JSON.stringify({
                found: true,
                sys_id: gr.getUniqueValue(),
                legal_name: gr.getValue('legal_name'),
                first_name: gr.getValue('first_name'),
                middle_name: gr.getValue('middle_name'),
                last_name: gr.getValue('last_name'),
                d_o_b: gr.getValue('d_o_b'),
                phone_number: gr.getValue('phone_number'),
                email: gr.getValue('email'),
                age: gr.getValue('age'),
                gender: gr.getValue('gender'),
                street_address: gr.getValue('street_address'),
                city: gr.getValue('city'),
                state: gr.getValue('state'),
                zipcode: gr.getValue('zipcode')
            });
        }

        return JSON.stringify({
            found: false
        });
    },

    type: 'ClientLookup'
});
Client script for phone and dob save correctly for each item.
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue == '') {
        return;
    }

    var dob = g_form.getValue('d_o_b');
    var phone = g_form.getValue('phone_number');

    if (!dob || !phone) {
        g_form.setValue('u_client_found', 'false');
        g_form.setValue('status', 'new_client');
        return;
    }

    var ga = new GlideAjax('ClientLookup');
    ga.addParam('sysparm_name', 'getClientByDobAndPhone');
    ga.addParam('sysparm_dob', dob);
    ga.addParam('sysparm_phone', phone);

    ga.getXMLAnswer(function(response) {
        if (!response) {
            g_form.setValue('u_client_found', 'false');
            g_form.setValue('status', 'new_client');
            g_form.addErrorMessage('No response from client lookup');
            return;
        }

        var answer = JSON.parse(response);

        if (answer.found) {

            g_form.setValue('client', answer.sys_id);
            g_form.setValue('legal_name', answer.legal_name);
            g_form.setValue('first_name', answer.first_name);
            g_form.setValue('middle_name', answer.middle_name);
            g_form.setValue('last_name', answer.last_name);
            g_form.setValue('email', answer.email);
            g_form.setValue('gender', answer.gender);  
            g_form.setValue('age', answer.age);
            g_form.setValue('street_address', answer.street_address);
            g_form.setValue('city', answer.city);
            g_form.setValue('state', answer.state);
            g_form.setValue('zipcode', answer.zipcode);

            g_form.setValue('u_client_found', 'true');
            g_form.setValue('status', 'existing_client');

            g_form.addInfoMessage('Client found');

        } else {

            g_form.setValue('u_client_found', 'false');
            g_form.setValue('status', 'new_client');

            g_form.addErrorMessage('Client not found');
        }
    });
}
 Catalog script ( html involved)
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading) {
        return;
    }

    if (!newValue) {
        g_form.setValue('product_preview', '');
        return;
    }

    var ga = new GlideAjax('SkinEnvyOrderProductLookup');
    ga.addParam('sysparm_name', 'getProductsDetails');
    ga.addParam('sysparm_product_sysids', newValue);

    ga.getXMLAnswer(function(answer) {
        var data = JSON.parse(answer || '[]');

        if (!data.length) {
            g_form.setValue('product_preview', '');
            return;
        }

        var html = '';
        var total = 0;

        for (var i = 0; i < data.length; i++) {
            var product = data[i];
            var price = parseFloat(product.price || 0);
            total += price;

            html += ''
                + '<div style="display:flex; align-items:flex-start; gap:16px; border:1px solid #ddd; padding:12px; margin-bottom:12px; border-radius:8px;">'
                +   '<div style="flex:0 0 150px;">'
                +       (product.image ? '<img src="' + product.image + '" style="max-width:150px; max-height:150px;" />' : '')
                +   '</div>'
                +   '<div style="flex:1;">'
                +       '<div style="font-weight:bold; margin-bottom:8px;">' + (product.name || '') + '</div>'
                +       '<div><strong>SKU:</strong> ' + (product.sku || '') + '</div>'
                +       '<div><strong>Price:</strong> $' + price.toFixed(2) + '</div>'
                +       '<div style="margin-top:6px;"><strong>Description:</strong> ' + (product.description || '') + '</div>'
                +   '</div>'
                + '</div>';
        }

        html += '<div style="font-weight:bold; font-size:16px; margin-top:12px;">Estimated Total: $' + total.toFixed(2) + '</div>';

        g_form.setValue('product_preview', html);
    });
}



1 REPLY 1

Naveen20
ServiceNow Employee

 

1. GlideAjax behaves differently in Service Portal

Your client scripts use GlideAjax which works in SP, but with some caveats. Make sure both Script Includes (ClientLookup and SkinEnvyOrderProductLookup) have the Client callable checkbox enabled. Without that, SP will block the AJAX call and throw a console error. Also, if these Script Includes live inside your scoped app, ensure the scope's cross-scope access is configured to allow client-callable requests from SP.

2. Raw HTML injection won't render in Service Portal

This is most likely your main issue. In your catalog client script you're doing:

g_form.setValue('product_preview', html);

The platform UI will render that raw HTML in an HTML field, but Service Portal sanitizes HTML content set through g_form.setValue() for security reasons. So your product preview with <div>, <img>, and inline styles will either be stripped out or cause a rendering error. In SP, the recommended approach is to use a widget with an ng-bind-html directive combined with the $sce.trustAsHtml() service, or redesign using a variable type that SP supports natively (like a macro or a UI page embedded in the catalog item).

3. Check your browser's developer console for the actual error

Press F12 → go to the Console tab, reproduce the issue, and look at the red error message. It will tell you exactly which script is failing. Common errors you'll see are:

  • "Access denied" or "not client callable" → Script Include isn't marked Client callable
  • "JSON.parse: unexpected character" → GlideAjax is returning XML/HTML instead of your expected JSON (often because the Script Include can't be found)
  • "TypeError: Cannot read property..." → A g_form.setValue() call is referencing a variable name that doesn't exist on the SP catalog item form

4. Suggested fix for the HTML rendering

Instead of building raw HTML in the client script, return the structured JSON data and use an Angular template in a catalog item widget to render it. Alternatively, if you must keep the current approach, use a Macro variable type or an embedded widget to display the product preview content safely in SP.

5. Verify the navigation URL

You mentioned the "Create appt" button ports to the Service Portal. If you're building the URL manually (e.g., window.location = '/sp?id=sc_cat_item&sys_id=...'), make sure you're passing all required parameters correctly and that the target catalog item is accessible through the Service Portal's catalog. A missing or incorrect sys_id will trigger a generic SP error page.