petercawdron
Kilo Guru

ServiceNow provides a client-side API called GlideModal but the documentation is focused around displaying records or lists from ServiceNow. There are times where you'd like to use a custom form with just a few options. In this example, we're adding a UI Action button to the catalog task form so when a task is cancelled we can either:

  • Closed skipped - effectively cancelling just this task
  • Closed incomplete - close this and all other tasks along with the requested item itself

In this way, we're giving our users the ability to clearly determine what they're cancelling. Just one particular task or the whole thing.

find_real_file.png

UI Actions allow you to run code client-side and server-side, which is very handy. 

The key to getting some flexibility with your modal dialog is the renderWithContent which allows us to craft our own HTML and the window.changeTaskAction which allows us to interpret whatever happened on our modal as the user interacted with our options.

////////////////////////////////////////////////////////////////
//Client Side: Dialog box with choices
////////////////////////////////////////////////////////////////
function cancelDialog(){

	var gm = new GlideModal('cancelTask');
	//Sets the dialog title
	gm.setTitle('Cancel Task'); 
	//Set up valid custom HTML to be displayed
	gm.renderWithContent('<div style="padding:15px"><p>What action do you want to take?</p><p><select name="cancellation" id="taskCancellation" class="form-control"><option value="cancelOnly" role="option">Cancel this task but keep the requested item open</option><option value="cancelAll" role="option">Cancel this and all other tasks, closing the requested item</option></select></p><div style="padding:5px;float:right"><button style="padding:5px;margin-right:10px" onclick="window.changeTaskAction(this.innerHTML,jQuery(\'#taskCancellation\').val())" class="btn btn-default">Abort</button><button  style="padding:5px" class="btn btn-primary" onclick="window.changeTaskAction(this.innerHTML,jQuery(\'#taskCancellation\').val())">Cancel Task</button></div></div>'); 

	//We'll use the windows object to ensure our code is accessible from the modal dialog
	window.changeTaskAction = function(thisButton, thisAction){
 
		//Close the glide modal dialog window
		gm.destroy();

		//Submit to the back-end
		if(thisButton=='Cancel Task'){
			if(thisAction=="cancelAll"){
				g_form.setValue('state',4);//Closed Incomplete -- will close the Requested Item and all other open tasks
			}else{
				g_form.setValue('state',7);//Closed Skipped -- will only close this task
			}
			//Regular ServiceNow form submission
			gsftSubmit(null, g_form.getFormElement(), 'cancel_sc_task');
		}
	};
	return false;//prevents the form from submitting when the dialog first loads
}

////////////////////////////////////////////////////////////////
//Server Side: Dialog box with choices
////////////////////////////////////////////////////////////////
if (typeof window == 'undefined')
	updateTask();

function updateTask(){
	//Runs on the server
	if(current.state==7){
		//closed skipped so simply update this one record
		current.update();
	}else{
		//closed incomplete so update all associated records to close the requested item entirely
		current.update();

		//And now we'll cancel any other open tasks along with the requested item
		if(!gs.nil(current.parent)){
			//Close siblings
			var otherTasks = new GlideRecord('sc_task');
			otherTasks.addEncodedQuery('request_item='+current.request_item+'^stateIN-5,1,2');
			otherTasks.query();
			while(otherTasks.next()){
				otherTasks.state = '4';
				otherTasks.update();
			}
			//Close parent
			var ritm = new GlideRecord('sc_req_item');
			if(ritm.get(current.parent)){
				ritm.state = '4';
				ritm.stage = 'Cancelled';
				ritm.update();
			}
		}
	}
}

Code like this can be easily retrofitted to provide you with a good template for interacting with users before you save your record. 

If for some reason the attached UI Action doesn't work, toggle the "isolate script" field (save it on then off) and it should run just fine.

Have fun.

Comments
DeeC
Kilo Contributor

I tried this in a scoped app but doesn't work. Same exact code on catalog task record works. Do you know if there is way to make it work for scoped apps?

Dan Ellis
Kilo Sage

It is probably the "window.changeTaskAction" part of the code that is not working in the scope.

You can achieve much of the same behaviour with GlideModal by using a UI Page rather than using "renderWithContent".

By using a UI Page you do not need to be listening to the modal changes inside of the UI Action as your scripts will go inside the UI Page's own client script.

Just remember that you won't have access to the "current" object but you could pass some values into the UI Page using "setPreference". For example pass in the parent sys_id and then your UI Page can perform a GlideRecord query to retrieve the record.

epinetti
Tera Guru

I had the same issue. The Ui Action was not working directly. The solution i found, in my case was modify the way to call the JS function 

 

window.changeTaskAction = function(thisButton, thisAction

by

top.window.changeTaskAction = function(thisButton, thisAction

 

and all the HTML codes

onclick="window.changeTaskAction(this.

by

onclick="top.window.changeTaskAction(this.

 

Due a scope security reasons the function has not access to  be called as a window object at the client scripts. You have to use TOP

 

Let me know if that helps

Stan Martin
Kilo Guru

It sure did help me.  I was using the same script that Peter mentioned at the top of this thread and it worked fine in my PDI, but when I moved it to our regular Dev instance it quit working.

Thx for this.

Stan Martin
Kilo Guru

Is the value of thisAction available to the server side.  I'm needing to take the selected value of the dropdown and create a new record in another table using what was selected.

petercawdron
Kilo Guru

Stan, yes, the server side code could be modified to create new records on-the-fly. Don't forget to take into account the code changes above if you run into problems with the modal button not closing properly.

sgmartin
Kilo Guru

Peter,

Thx for responding.  I actually found a way to get to what I wanted by calling a Script Include using GlideAjax and passing the value of thisAction as a parameter.  A single dropdown like in your example was pretty straightforward.  Now I have to create one with 2 dropdowns.  

I see:

window.changeTaskAction = function(thisButton, thisAction)

thisButton is the button clicked and thisAction is the vale of the dropdown.  Can there be more than 1 value in the case of 2 dropdowns?

petercawdron
Kilo Guru

As you're introducing more functionality, I'd recommend using event listeners. This will allow you to distinguish between events and the data associated with them. Check out this example

Kevin Paul
Mega Guru

I have used this glide modal to display a list of records. However the list of records are shown in columns that I don't need really. I need it to display certain columns that I feel are important. When I tried using personalize list icon, it did not work. How can I achieve what I need?

Kevin S2
Tera Contributor

Im trying to repurpose this to work on the incident form and everything seems to be okay with rendering the HTML and modal but none of the buttons are responding. 

petercawdron
Kilo Guru

Try logging to the console within window.changeTaskAction to see what's happening, ie.

console.log('this button and action were undertaken');
console.log(thisButton);
console.log(thisAction);

 

-Andrew-
Kilo Sage

Brilliant, thank you Peter!!!!!!!!!!

kpadishala
Tera Contributor

Hi Peter,

 

In our instance there is a customization made in UI Action for the visibility of Dialog window with drop down list to opt.

The drop down list within the dialog box (which was made up with the syntax line "var dialog = GlideModal ? GlideModal : GlideDialogWindow;" followed by calling the list) is only accessible to the "admin" role users, other than admin role users can able to see the dialog window but not able to access/opt the drop down list values.

 

Could you please help me by guiding the resolution for this issue.

kpadishala
Tera Contributor

Hi @petercawdron,

 

In our instance there is a customization made in UI Action for the visibility of Dialog window with drop down list to opt.

The drop down list within the dialog box (which was made up with the syntax line "var dialog = GlideModal ? GlideModal : GlideDialogWindow;" followed by calling the list) is only accessible to the "admin" role users, other than admin role users can able to see the dialog window but not able to access/opt the drop down list values.

 

Could you please help me by guiding the resolution for this issue.

Version history
Last update:
‎03-01-2020 08:01 PM
Updated by: