The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Willem
Giga Sage
Giga Sage

Get XML wait

For those of you that are not familiar with GlideAjax. getXMLWait() is a Synchronous GlideAjax call. Meaning your  script cannot continue without the GlideAjax response. This stops the session until the response is received.

How to use getXMLWait

Scenario

If we look at a scripting example. Lets say we want to do some checks onSubmit of a Catalog item. In our case, we want to validate the user is part of a company. If the user is not part of the company, we want to abort the Catalog Item request and show an error message. To do this, we can use a Script Include to handle the Server lookup and an onSubmit Catalog Client script that prevents submission. We do not want to continue submission until we get a response from the Server back, stating it is alright.

 

The script

To do this we can write the following Client Callable script include. If you want to do a different validation, you can change it.

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

    checkCompany: function () {
        var answer = false;
        var user = this.getParameter('sysparm_user');
        var gr = new GlideRecord('sys_user');
        gr.addQuery('sys_id', user);
        gr.addQuery('company.name', "ACME North America");
        gr.query();
        if (gr.next()) {
            answer = true;
        }
        return answer;
    },

    type: 'catItemHelper'
});

 

As an onSubmit client script we have the following script:

function onSubmit() {
    var user = g_user.userID;
    var ga = new GlideAjax('catItemHelper'); //Name of the Script Include 
    ga.addParam('sysparm_name', 'checkCompany'); //name of function in script include 
    ga.addParam('sysparm_user', user);
    ga.getXMLWait();
    var answer = ga.getAnswer();
    if (answer == 'false') {
        g_form.addErrorMessage('Only users from company ACME North America are allowed');
        return false;
    }
}

 

The result

User has company "ACME North America":

find_real_file.png

 

 

User does not have company "ACME North America":

find_real_file.png

The issue

getXMLWait() is not supported by the Service Portal:

https://docs.servicenow.com/bundle/orlando-servicenow-platform/page/build/service-portal/reference/c...

 

When we try the same item in the Service Portal we get the following:

find_real_file.png

 

In the console:

find_real_file.png

To prevent the error from appearing we can set our Client Script as UI Type Desktop. Because that is where the script is working:

find_real_file.png

 

We do not get the popup anymore, but the validation is also not happening anymore on the Service Portal.

 

Asynchronous Ajax call

In the Service Portal Asynchronous Ajax calls are supported.

The issue with these Asynchronous Ajax calls however, is that the script will not wait for the Server response. Meaning the Catalog Item will continue to be submitted, before we have a response back from the Server. So the validation we want will not work.

 

The solution

When the user clicks the submit button, we can return false, which will stop submission. We also trigger the Ajax call to the server. In the Callback function that handles the response (asynchronous) we can trigger the Submit from script again. But this time, if the response from the Server is not false, we set g_scratchpad.isFormValid to true. Which results in the script returning true and allowing us to submit the item.

To do this we add the following onSubmit Catalog Client Script. UI Type: Mobile/Service Portal:

function onSubmit() {
    if (g_scratchpad.isFormValid)
        return true;
    var user = g_user.userID;
    var ga = new GlideAjax('catItemHelper'); //Name of the Script Include 
    ga.addParam('sysparm_name', 'checkCompany'); //name of function in script include 
    ga.addParam('sysparm_user', user);
    ga.getXMLAnswer(setAnswer);
    return false;


    function setAnswer(answer) {
        if (answer == 'false') {
            g_form.addErrorMessage('Only users from company ACME North America are allowed');
            return false;
        }
        var actionName = g_form.getActionName();
        g_scratchpad.isFormValid = true;
        g_form.submit(actionName);

    }
}

 

The result

User has company "ACME North America":

find_real_file.png

 

User does not have company "ACME North America":

find_real_file.png

 

Comments
Vivek Verma
Kilo Sage
Kilo Sage

Now, this is the best solution for the synchronous approach on Portal. 

THanks,

Vivek || LinkedIn || Medium

Willem
Giga Sage
Giga Sage

Thank you! Feel free to bookmark and share with others! 🙂

find_real_file.png

Vivek Verma
Kilo Sage
Kilo Sage
Khanna Ji
Giga Guru

Wonderful article... Saved my life...

Willem
Giga Sage
Giga Sage

Hahaha glad my article helped save your life! 🙂

marcelveerkamp
Tera Contributor

Nice workaround! Great job, really helped me out there.

Khanna Ji
Giga Guru

Hi Willen,

I was just wondering if its possible to show a processing image or something until the get XML response is returned? This is because form is not doing anything until the response is returned and users might get an impression that nothing is happening.

Fred van der Sc
Kilo Contributor

Hi Willem,

 

I like this solution! Thanks!

Rick van Gelove
Tera Explorer

Hi Willem,

 

good solution as I also experienced the getXMLWait not working. This is a very useful workaround.

The SN Nerd
Mega Sage
Mega Sage

Very clever little workaround.

jeffersoncn
Tera Contributor

The best workaround I found to replace the using of getXMLWait on scoped applications. Thanks!

Ravi Katiyar
Kilo Expert

If someone is looking for official documentation please refer Knowledge Article reference from ServiceNow KB0783579

Tejaswini9
Tera Expert

Very helpful:)

Nikita40
Tera Contributor

Very helpful.

But how can we return more than one value from Script include in this case 

Willem
Giga Sage
Giga Sage

You can for example return an object from your script include. Adjust the Client script accordingly:

In below example the Server returns an object. One of the properties in that object is pass (or you can name it whichever you like).

So:

var obj = {
    pass: true,
    second_value: "your value",
    third_value: "your other value"
}

 

Then in the client script you check if answer.pass

function onSubmit() {
    if (g_scratchpad.isFormValid)
        return true;
    var user = g_user.userID;
    var ga = new GlideAjax('catItemHelper'); //Name of the Script Include 
    ga.addParam('sysparm_name', 'checkCompany'); //name of function in script include 
    ga.addParam('sysparm_user', user);
    ga.getXMLAnswer(setAnswer);
    return false;


    function setAnswer(answer) {
        var answerObj = JSON.parse(answer);
        if (answerObj.pass == 'false') {
            g_form.addErrorMessage('Only users from company ACME North America are allowed');
            return false;
        }
        var actionName = g_form.getActionName();
        g_scratchpad.isFormValid = true;
        g_form.submit(actionName);

    }
}

 

Hope this helps! 🙂

(If so mark helpful and the article as well! :D)

Nikita40
Tera Contributor

Thank you for your quick response

but its not working

It is giving error like "There is a JavaScript error in your browser console"

Willem
Giga Sage
Giga Sage

Can you share the error you get?

Nikita40
Tera Contributor

find_real_file.png

Nikita40
Tera Contributor

onSubmit client script is as follow

function onSubmit() {
if (g_scratchpad.isFormValid)
return true;
if ((g_form.getValue("please_select_one_of_the_below_options") == " Incident") ) {
var ga = new GlideAjax('ValidateINC');
ga.addParam('sysparm_name', 'checkIncident');
ga.addParam('sysparm_user', g_form.getValue('incident_ticket'));
ga.getXMLAnswer(setAnswer);
return false;
}

}

function setAnswer(answer) {
var answerObj = JSON.parse(answer);
if (answerObj.pass == 'false') {
g_form.addErrorMessage('Incident Ticket ' + answerObj.esc + ' is already created for the issue');
return false;
}
}
var actionName = g_form.getActionName();
g_scratchpad.isFormValid = true;
g_form.submit(actionName);

 

Script include is as follow

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

checkIncident: function() {
var answer = true;
var inc = this.getParameter('sysparm_user');
var gr = new GlideRecord('table_name');
gr.addQuery('u_reference_1.sys_id', inc);// u_reference_1 is field on table_name table
gr.query();
if (gr.next()) {
var obj = {
pass: false,
esc: gr.getValue("number")
};
}
return answer;
},

type: 'ValidateINC'
});

Willem
Giga Sage
Giga Sage
Update your script include. It should return obj (as a string). So: return JSON.stringify(obj);
Nikita40
Tera Contributor

still getting same error

Willem
Giga Sage
Giga Sage
Can you open a question for this and post the code. Feel free to tag me and I will check your script for further errors.
Mrman
Giga Guru

Hi ,

Please let me know what solution you have used to show a processing image or something until the get XML response is returned?

 

I am also facing same issue when we click Submit for a record producer , form is not doing anything until the response is returned

Kiran Ramanna
ServiceNow Employee
ServiceNow Employee

2 options:

1. put everything in a JSON object, stringify it in script include before return and JSON.parse in client script side.

2. Use json.encoding : https://community.servicenow.com/community?id=community_question&sys_id=b1a2d7a1db101fc01dcaf3231f961927

ArcRaj
Giga Contributor

Hi Team,

My onSubmit client script not working on service portal

I have catalog item where user will be selecting a group name ,

And if the current logged in user is the group manager of the user selected group then user should be able to place the request if not we should restrict the user from placing order.

Below is my code

CLIENT SCRIPT

function onSubmit() {
if (g_scratchpad.isFormValid)
{
return true;
}
var user = g_user.userID;
var group = g_form.getValue('group_name');
alert(group);
var gajax = new GlideAjax('TESTMANAGER'); // replace your script include name here
gajax.addParam('sysparm_name','isManager'); // replace function name here
gajax.addParam('sysparm_group',g_form.getValue('group_name'));
gajax.addParam('sysparm_user',user);
gajax.getXMLAnswer(setAnswer);
return false;
function setAnswer(answer) {
if (answer == 'false') {
alert(answer);
g_form.addErrorMessage('Only group managers can place a request');
return false;
}
alert('true');
var actionName = g_form.getActionName();
g_scratchpad.isFormValid = true;
g_form.submit(actionName);

}
}

SCRIPT INCLUDE

var TESTMANAGER = Class.create();
TESTMANAGER.prototype = Object.extendsObject(AbstractAjaxProcessor, {
isManager: function() {

var answer=false;
var user = this.getParameter('sysparm_user');
var group = this.getParameter('sysparm_group');
var grGroup = new GlideRecord('sys_user_group');
grGroup.addQuery('sys_id',group);
grGroup.addQuery('manager',user);
grGroup.query();
if(grGroup.next()) {
answer =true;
}
return answer;
},

type: 'TESTMANAGER'
});

 

-->Whenever group manager matches with the current logged- in user, I 'am getting the alerts and form is submitted as expected,But when they does not match I 'am not even receiving the alert statements.

-->And when I 'am  selecting  group manager different from the current logged -in user for the first time when form loads then it works as expected(only first i.e., when form loads, and when the values are changed same as usual no alerts and form is submitted.

Please suggest and help

Thanks in Advance

AnirudhKumar
Kilo Sage
Kilo Sage

You are a genius! 🙂

Adiseshu Borra
Tera Expert
Great Article.
Prathamesh4
Giga Explorer

Thanks for help..

GeoffreyOptumOp
Tera Expert

Very smart, and nicely described; Thank you.  However...

I kind of HATE that this is necessary, and I can see this being pretty confusing for someone who comes after you.

It seems like ServiceNow is terrified of synchronous calls to the server, and is bending over backwards to prevent anyone from doing anything which could "block" the client, even for a few milliseconds.  I don't know why they are doing that.  Were there horrible problems with this in the past?

What you have shown seems like a valid use-case.

Because ServiceNow hasn't provided a standard method for doing this type of synchronous action, now we are in a game of Cat and Mouse, where ServiceNow tries to prevent its customers from doing something, and then their customers invent new ways (like this) of doing it.

Mario M_ Junior
Mega Explorer

I was stuck for over 2 hours trying to find a solution, your article solved it perfectly.

Thank you very much! 😀

Kamil Smusz
Tera Guru

Hi,

 

Not sure if it's dependent on version but on Quebec if answer function return true i need to click again on submit button because actionName variable return "none". I fix it by putting 'submit' in g_form.submit() function.

 

 g_scratchpad.isFormValid = true;
 g_form.submit('submit');

 

Shahebaz
Tera Expert

@Kamil Smusz Thank You, It works 

Kartik Choudha1
Tera Guru

Hey, 

Thanks for this article. I have used the same approach for one of my requirement.

 

Just wanted to confirm, Whether it comes under best practice of servicenow or not? OR it has any other impacts?

 

Regards,

Kartik

JLeong
Tera Guru

Thank you! Great explanation!

Sathiskumar_D
Giga Sage

@Will

This guy @amitgujarathi is using your content but not giving credit. Besides, he is claiming as his! This is very unfair. This is plagiarism!!!

Steve56
ServiceNow Employee
ServiceNow Employee

Hi, i don't know if this thread is still active but here's an issue that I encountered:

 

The script successfully blocks submission when the Ajax returns false. However, when I change the value to true and submit the form again, the console will continuously throw this warning (over 1000 times) and never submit it.

 

Overwriting extension point: g_validation_script_field_count

 

Does anyone know how to solve this issue and why this is a thing?

Varun Sharma
Tera Contributor

Hi Willem, 

 

i know it's been a while , but this method doesn't work with Multirow variable set. 

do you have any idea how should i approach this , as i want to add delay. 

 

Regards, 

 

Varun Sharma

sabell2012
Mega Sage
Mega Sage

So, I didn't see it mentioned, but why was xmlwait removed in the first place. I just did a look at the base code and ServiceNow still uses it (in Global) in 39 client scripts. So the question: why get rid of an important and valuable tool in the platform?  BTW, it solves the very problem that was brought up as an example in this article (nice job btw on the workaround Willem).

The SN Nerd
Mega Sage
Mega Sage

getXMLWait() can't be used in Configurable Workspace either.

MYousaf111
Tera Contributor

This method is really helpful for simple client script. But my question is how can we use this method in Catalog Client Script, because we cannot use g_form.Submit and g_scratchpad in catalog client script. 

pespinar
Tera Contributor

Hi @Willem,

 

great piece of code. I have one question: why do you use your code for Portal only? It should not work in Desktop also, saving us to use two client scripts?

Regards,

Pablo Espinar 

Haresh Haru
Tera Expert

Hello @Willem 

 

I have followed the solution which you have provided it's working as expected but one thing I am getting one error like when user clicks on submit button in portal to submit the request first time the submission is not happening and when we click on again submit button that time it's gets submitted.

Could please suggest me it's need to submit at first time user clicks on submit button..

 

Regards,

Haresh

Kamil Smusz
Tera Guru

hi @Haresh Haru,

 

try this one

 

Not sure if it's dependent on version but on Quebec if answer function return true i need to click again on submit button because actionName variable return "none". I fixed it by putting 'submit' in g_form.submit() function.

 

 g_scratchpad.isFormValid = true;
 g_form.submit('submit');

 

Haresh Haru
Tera Expert

Hello @Kamil Smusz 

 

Can you please tell me in this client script  i have put this code but it's not working as expected it's submitted without validation the condition..

 

function onSubmit() {
    if (g_scratchpad.isFormValid)
        return true;
    //var user = g_user.userID;
    var fname = g_form.getValue('first_name');
    var lname = g_form.getValue('last_name');
    var ga = new GlideAjax('GuestUserCheck'); //Name of the Script Include
    ga.addParam('sysparm_name', 'getInfo'); //name of function in script include
    ga.addParam('sysparm_user_fname', fname);
    ga.addParam('sysparm_user_lname', lname);
    ga.getXMLAnswer(setAnswer);
    return false;


    function setAnswer(answer) {
        //alert(answer);
        if (answer == true) {
            g_form.addErrorMessage('The guest user already exists in the user table');
            return false;
        }
        var actionName = g_form.getActionName();
        g_scratchpad.isFormValid = true;
        g_form.submit(actionName);
         g_form.submit('submit');

    }
}
 
Regards,
Haresh
Kamil Smusz
Tera Guru

hi @Haresh Haru 
looks like you need to comment 2 lines like below

function setAnswer(answer) {
        //alert(answer);
        if (answer == true) {
            g_form.addErrorMessage('The guest user already exists in the user table');
            return false;
        }
        //var actionName = g_form.getActionName();
        g_scratchpad.isFormValid = true;
        //g_form.submit(actionName);
         g_form.submit('submit');

 

Haresh Haru
Tera Expert

Hello @Kamil Smusz 

 

I have commented out and I tried also but it's not working like it's throwing when condition meet but it's not submitting if I click on several times 

 

 

Kamil Smusz
Tera Guru

hi @Haresh Haru,

 

Have you checked if you if function is working? Can you show me what you returning in Script Include ?

Haresh Haru
Tera Expert

Hello @Kamil Smusz 

 

Please find my script include and client script aswell and help me on this ..

 

 

Script include : 

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

    getInfo: function() {

        var userfname = this.getParameter('sysparm_user_fname');
        var userlname = this.getParameter('sysparm_user_lname');
        var results = {};

        var user = new GlideRecord('sys_user');
        user.addEncodedQuery('first_name='+ userfname+'^last_name='+userlname+'^u_userid_local_idSTARTSWITHc');
        user.query();

        if (user.next()) {
            return true;
        }
        else return false;

    },

    type: 'GuestUserCheck'

});
 
 
Client script :
 
function onSubmit() {
    if (g_scratchpad.isFormValid)
        return true;
    //var user = g_user.userID;
    var fname = g_form.getValue('first_name');
    var lname = g_form.getValue('last_name');
    var ga = new GlideAjax('GuestUserCheck'); //Name of the Script Include
    ga.addParam('sysparm_name', 'getInfo'); //name of function in script include
    ga.addParam('sysparm_user_fname', fname);
    ga.addParam('sysparm_user_lname', lname);
    ga.getXMLAnswer(setAnswer);
    return false;


    function setAnswer(answer) {
        //alert(answer);
        if (answer == 'true') {
            g_form.addErrorMessage('The guest user already exists in the user table');
            return false;
        }
       //var actionName = g_form.getActionName();
         g_scratchpad.isFormValid = true;
       // g_form.submit(actionName);
        g_form.submit('submit');


    }
}
 
Kamil Smusz
Tera Guru

hi @Haresh Haru 

 

please update your script include like below

       if (user.next()) {
            return 'true';
        }
        else return 'false';
Haresh Haru
Tera Expert

Hello @Kamil Smusz 

 

Awesome, Now it's working as expected thanks a lot for your support.

Regards,

Haresh 

Version history
Last update:
‎09-20-2020 06:04 AM
Updated by: