GeoffreyOptumOp
Tera Expert

- Yes, you can have a single UI Action that runs both Client-Side and Server-Side code. This is necessary sometimes, for example in the case where you want to check additional conditions or gather additional information from the user After he clicks the UI Action but Before you pass control back to the server.

- Yes, the way it is done is fairly convoluted because both Client-Side and Server-Side script is defined in the very same script block; so only Some of the code applies Some of the time.

- Yes, this has been discussed at length, by smarter people than I, here, but I found the examples difficult to follow, so I made my own in this article, and this may help others...  Here is how you do it in Quebec:

find_real_file.png

1.  Check the "Client" checkbox.  Normally UI Actions run only on the server, so this checkbox tells ServiceNow to run this on the client instead.  But actually you will write both client-side and server-side code in the script block.

2.  Define a function which will be called ONLY when the UI Action is clicked.  (Not when it is rendered.)

3.  Give your action a name.  You will need to reference this name in the script itself.  Basically, the UI Action script will "call itself", but the 2nd time it is invoked, it will be run on the server, not the client.

4.  Define the script portion of your UI Action, as follows:

/*
In a UI Action, when code is declared outside of any function block, that code runs EACH TIME
the UI action is RENDERED on the client, even before the UI action is clicked.  The code will
be run once if you check the box "Form Link".  It will be run AGAIN if you check the box
"Form context menu", and yet AGAIN if you check "Form button".  Etc.
*/

//If this code is being run in the context of the SERVER...
if(typeof window == 'undefined')
{
	//Use only Server-Side objects and functions in this IF block
	//and in the functions called from this IF block.
	gs.addInfoMessage("4.  UI Action Script running Server Side.");
	runServerSideCode();
}
//Else, this code is being run in the context of the CLIENT so...
else
{
	/*
	Normally this ELSE block will not be necessary and will not have any value,  but it may
	help to uncomment the alert() here to understand that this code runs every time the 
	UI Action is rendered.  If you do have code in this ELSE block, use only Client-Side
	objects and functions in it and in any functions called from this ELSE block.
	//alert("Functionless UI Action Script running Client Side.  (UI Action Rendered)");
	*/
}

//IMPORTANT. This function name must be populated in the UI Action's "Onclick" field.
function runClientSideCode()
{
	alert("1.  UI Action clicked.  Client Side Code Activated.");
	
	var bConditionPassed = confirm("Are you sure you wish to continue???");
	if (! bConditionPassed)
	{
		alert("2.  Aborting UI Action.  Script terminating now.");
		return false;
	}

	alert("3.  Continuing forward.  Calling gsftSubmit()");
	//Use gsftSubmit to rerun this very same UI action, but this time
	//the code will run on the Server.
	//IMPORTANT. Parameter 3 is the name of this UI Action, set in the "Action name" field.
	gsftSubmit(null, g_form.getFormElement(), "My_Unique_UI_Action_Name");
}

function runServerSideCode()
{
	gs.addInfoMessage("5.  Server Side function Activated.");
	
	//TBD.  Place your custom code Server-Side code HERE,
	//using only server-side objects such as "current" and "GlideRecord".
	
	gs.addInfoMessage("6.  Server Side Code COMPLETE.");
}

Please mark this article as Helpful if it helped you.

Also, if there is a BETTER / NEWER way to do this now (perhaps in Rome (?)) please let me know what that is!

Thanks!

Comments
VagelieK
Tera Contributor

Does this have the ability to pass variables between client and server sections, and is the order of operations manageable?  I see in your example the process is client THEN server.  Is it possible to do client, server, client, redirect?

I am looking for the functionality you define here, for an agent workspace UI action, but also receiving the sys_id the server side GlideRecord generated, and adding that to something like:

 

top.window.open('/<tablename>_task.do?sys_id=' + <transferredvariable>.sys_id,'_blank'); 

within the client script, AFTER the server script runs, routing the user to the newly created GlideRecord item.

Essentially, I am wondering if this is feasible, or would be better suited with a client script calling a script include and leveraging GlideAjax instead?

Anitha K
Tera Explorer

The sample script you shared was extremely helpful, especially the function names you used, the alert and info messages to understand the sequence. Thanks a lot! 🙂 @GeoffreyOptumOp 

Version history
Last update:
‎11-16-2021 03:30 PM
Updated by: