Client & Server Code in One UI Action

Most Service-now administrators and consultants know how to configure and use UI Actions. UI Actions are UI elements that can show up on a form or a list as a button, link, or context menu. When these UI elements are clicked they execute some JavaScript. Most of the time UI Actions are used to perform some server-side update to a record or records. In other cases, you can use the ‘Client’ checkbox on the UI Action record to execute some client-side JavaScript (including checking for mandatory fields).

But what if you need to do both? The classic case is when you want to click a button to make an update to a record, but only if the user has provided the correct input first. An example would be a ‘Reopen Incident’ button that changes the state on an incident record from ‘Resolved’ to ‘Active’. Usually you want to require the user to provide some sort of comment or additional information explaining why they are reopening the ticket. The problem is that you don’t always want the ‘Comments’ field to be mandatory so the validation needs to happen at the time the ‘Reopen Incident’ button gets clicked. Validation of mandatory fields needs to happen client-side but the update to your record needs to happen server-side. How can you accomplish both of these things with a single UI Action? This article shows you how.

The basic format for using a Client Script and Business Rule in the same UI Action looks something like this…

UI Action Template
Name: -Button Name-
Action name: -button_action_name- (Should be unique per button on form and gets called from the UI Action script)
Client: True (MUST be checked)
Form button/Form Context Menu/Form Link: (UI Action must be one of these ‘Form’ types)
Onclick: -runClientCode();- (Points to the function in your script that should be run when the UI Action gets clicked)

//Client-side 'onclick' function
function runClientCode(){
if( == false){
return false; //Abort submission
//Call the UI Action and skip the 'onclick' function
gsftSubmit(null, g_form.getFormElement(), ''); //MUST call the 'Action name' set in this UI Action
}//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')
runBusRuleCode();//Server-side function
function runBusRuleCode(){
current. = ;
gs.addInfoMessage('You did it!');

So why does this work? I had to go to a Service-now developer to find out. The reason is that UI Actions can run scripts at two different times. The first time is when the UI Action gets clicked. When you define a ‘Client’ UI Action you also give that UI Action the name of a function in your ‘Script’ field to execute. This function has to be called explicitly (through the ‘onclick’ event) or it doesn’t run at all.
The second time is on the way to the server. This is how any UI Action without the ‘Client’ checkbox selected gets run. On the way to the server the entire UI Action script gets executed regardless of whether or not the ‘Client’ checkbox is checked. What this means is that any script you include in your UI Action that isn’t enclosed in a function will be run on the way to the server. The script above takes advantage of this fact by making a specific call to the ‘Client’ function, performing client-side validation, and then the UI Action calls itself if the client-side validation passes.
When the UI Action calls itself it bypasses the ‘onclick’ function because the button didn’t get clicked the second time. So the script continues to the first point where there is something to execute. At that point you can call your Server-side function! The only thing you need to be careful of is that you only call the Server-side function if the script isn’t running in the client anymore. That’s what the check in the middle does…and eliminates any browser errors saying that ‘current’ (or any other Server-side function or object) isn’t defined.

Here is a solution I’ve used in the past to give users the ability to reopen an incident record. The solution uses a UI Action button to check if the ‘Comments’ field has been filled in (this is the ‘Client-side’ portion). If the validation passes, then the incident record gets updated.

Reopen Incident UI Action

Note that this script uses the ‘State’ field rather than the ‘Incident State’ field. In my opinion, it is much better to consolidate all of your state fields into one using the ‘State’ field at the task level as described here.

Name: Reopen Incident
Action name: reopen_incident
Client: True
Form button: True
Onclick: reopen();
Condition: current.state == 6

//Client-side 'onclick' function
function reopen(){
if(g_form.getValue('comments') == ''){
//Remove any existing field message, set comments mandatory, and show a new field message
g_form.setMandatory('comments', true);
g_form.showFieldMsg('comments','Comments are mandatory when reopening an Incident.','error');
return false; //Abort submission
//Call the UI Action and skip the 'onclick' function
gsftSubmit(null, g_form.getFormElement(), 'reopen_incident'); //MUST call the 'Action name' set in this UI Action

//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')

function serverReopen(){
//Set the 'State' to 'Active', update and reload the record
current.state = 2;
gs.addInfoMessage('Incident ' + current.number + ' reopened.');

Date Posted:

May 20, 2021

Share This:


  1. Richard Huss August 31, 2010 at 2:12 am

    Ingenious – and somewhat simpler than the way the Incident Resolution best practice plugin does the same sort of thing to make close notes mandatory on resolution or closure. The (BP) Close Mandatory on Close or Resolve client script is quite dastardly.

  2. Ron Methias August 31, 2010 at 2:30 am

    Another reason why I have stopped going to the official SN documentation sites and make the GURU my documentation site of choice. You come up with clever solutions that every admin could use.

    This is really cool!

  3. Joe Watts September 8, 2010 at 6:21 pm

    So cool, makes it so much easier/cleaner to do confirm() before executing server-side code. Definitely something I will use all the time, thanks!

  4. Dhanraj P September 14, 2010 at 6:00 am

    Working perfectly…. thnks a lot for sharing this knowledge !!

  5. Thak March 7, 2011 at 9:35 pm


    I got a little problem with that script. Indeed, it works perfectly with buttons in the bottom of the form.

    But, my buttons in the title bar does not work. They launch the script client side but the ‘gsftSubmit’ action is inactive. Maybe because the button has no id (when selecting client for the UI Action, the action name is not associated to the id of the html button).

    Have you experienced that before?



    • Mark Stanger March 7, 2011 at 10:37 pm

      I haven’t seen the problem you describe before.

      • Thak March 13, 2011 at 9:33 pm

        For your information, I have solved my problem.

        As I expected, the problem was not coming from the code of that post. The point was coming from the List V2 plugin.

        I was using a embedded list in my form, and as that list was empty, it was raising the following error in my FF javascript console :

        this.tableElementDOM.rows[0] is undefined.

        And that error was in conflict with the gsftSubmit action, so that the form was not able to be submitted.

        Thanks for your quick answer.

        P.S : I raised that bug to SNC

        • Mark Stanger March 14, 2011 at 12:31 am

          Wow, that’s a strange one. Thanks for digging in and figuring it out. :)

          • Jim Coyne March 16, 2011 at 4:46 pm

            Cool, got it working with a confirmation before undertaking the actual action. I’m using gs.addInfoMessage do add an info/error message at the top of the screen to say the action was successful or not, but the client would prefer an alert window instead. Would that be possible?? Can’t see how – I tried adding an alert after the call to the server side code, but it actually pops up before the code is run.

          • Mark Stanger March 16, 2011 at 4:53 pm

            I don’t think that’s possible if you’re trying to add the message after the server-side code executes. You’ll need to use addInfoMessage for that final confirmation.

  6. Jim Coyne March 16, 2011 at 5:41 pm

    That’s what I figured. I used HTML to change the message to be pretty obvious and it takes up quite a bit of room at the top of the screen. If the user does not see it, then there’s a problem.


  7. John Gilaspy April 4, 2011 at 3:58 am

    I want to use this script, but I keep getting an error that g_form is undefined. Any ideas why?

    gsftSubmit(null, g_form.getFormElement(), ”);

    • Mark Stanger April 4, 2011 at 4:03 am

      The error suggests that you’re trying to run the script in a place other than a regular form. You won’t be able to get it to work from a UI page or a list for example. If you can set up a test on demo and reproduce there I can take a look.

  8. John Gilaspy April 4, 2011 at 4:29 am

    It works fine, once you close and reopen the browser. That was all it took.

  9. Abhiram Bharadwaj May 25, 2011 at 8:06 pm

    Fantastic ! Too Good.Thanks a lot Mark !

  10. Dhanraj Poojari July 23, 2011 at 1:19 pm

    Thanks Mark!!

  11. Russ Hart August 17, 2011 at 4:31 am

    Hi Mark,
    I’m trying to use this in conjunction with a dialog.render in the client side, before updating the record on the server side. The problem I’m having is that the gsftSubmit(null, g_form.getFormElement(), ‘cancel_request’); line is actioned as soon as the dialog box is rendered so the user doesn’t get the chance to fill in the dialog box. Is there a way I can make it wait for the OK button on the rendered dialog to be pressed before proceeding to the gsftSubmit ?

    • Mark Stanger August 17, 2011 at 10:38 am

      I’m not sure about the specifics of your setup, but it sounds like you need to have a ‘return false;’ line in your client-side piece of the UI action so that the bottom form doesn’t submit.

      • Russ Hart August 17, 2011 at 11:18 am

        Thanks Mark – unfortunately then the script stops so the server side part is never executed. I need it to still execute the server side part of the UI Action but only after the OK button on the dialog form is pressed.

  12. Russ Hart March 9, 2012 at 4:40 am

    Hi Mark – can you tell me if it’s possible to pass a variable (using var xxx = prompt(‘ask user a question’)) from within the client function to the server function (so I can push the variable value into multiple other records)? I tried declaring as a global variable but the server side can’t see the variable. Thanks

    • Mark Stanger March 9, 2012 at 6:27 am

      The only way I can think of to do that would be to set a value in a hidden field in your client script. Maybe you could set up a hidden field to store parameters temporarily just for that purpose.

      • James Brookes February 10, 2015 at 7:06 pm

        Setting the value in a hidden field (and saving the form) will not update the record with that value. Only the fields that are visible.

        Ruth’s idea below about using GlideAjax may be the only way to go.

        • James Brookes February 11, 2015 at 12:14 am

          Oh wait, no that was inaccurate. A hidden field will work, it just needs to be a part of the view.

  13. Hari October 1, 2012 at 4:59 am

    Hi Mark, can you tell me if the button of “Update selected” or “Update all” could be edited to generate a alert/waring and then perform updates.
    The requirement is to generate a pop-up after user clicks on “update button” not before.

    What I have noticed is the ‘update’ button has server side scripts which performs the updates and any changes done to the button(ui actions) through client callable just executes the client script but doesn’t execute the server scripts. I have even tried to create a new button and calling the update button using gstfsubmit (action_name of update button) it works fine but we need to hide that ‘update button’ but when I go back to ‘update button’ to hide it from my update view by using ‘ui action visibility’ it stops working.

    • Mark Stanger October 1, 2012 at 6:54 am

      I haven’t ever been able to find anything to control the behavior when using ‘Update selected’ or ‘Update all’. Unfortunately I think you’re stuck with the standard behavior there.

  14. Ruth Porter January 3, 2013 at 7:16 am

    Hi Mark,
    Bit of a slow response but with regard to Russ’s point about passing a variable to the server side: I have done this by using a GlideAjax call (which can be passed a variable) from the client side bit and having the server side bit just do what is left.

    Seems to work OK and gets rid of need for extra hidden field

    • Mark Stanger January 4, 2013 at 3:40 am

      Nice! Thanks for the good idea Ruth!

  15. Scott February 18, 2013 at 8:33 pm

    ok, I can officially confirm I am a scripting dumbo. I have tried various versions of this along with other articles that have similar functions and I cannot get it working. all I am trying to do is “confirm” that a user wants to create a problem record from the incident record, ie when they select the Create Problem UI Action on the Incident it pops up the confirm dialog, if Yes it continues with creating the PRB, if cancel it stays on the Incident. sounds simple right? not for this dumbo!

    • Mark Stanger February 19, 2013 at 6:32 am

      Scott, I just wrote an example script that should give you the exact structure you’re looking for. You’ll just have to convert it over to your UI action. Check out the update script here with the ‘Confirm’ message.

      • Scott February 19, 2013 at 9:29 pm

        THANKS MARK! You are a genius.. Your script made sense to me the more I read it. I think where I was falling over in my previous scripts was “NOT” calling, as I have shown in script below the “//server-side function” after doing the check for browser errors, simple mistake I was making and using the modified version (below) of your script woke me up to that.

        This is the script I ended up with and it works a treat.

        Action name: create_problem
        Client: True
        Form button: True
        Onclick: runClientCode();

        //Client-side 'onclick' function
        function runClientCode(){
          if(confirm('Are you sure you want to create a Problem Record?\n\nTHIS ACTION CANNOT BE UNDONE!')){
              //Call the UI Action and skip the 'onclick' function
              gsftSubmit(null, g_form.getFormElement(), 'create_problem'); //MUST call the 'Action name' set in this UI Action
              return false;
        //Code that runs without 'onclick'
        //Ensure call to server-side function with no browser errors
        if(typeof window == 'undefined'){
        //server-side function
        function CreateProblem(){
        var prob = new GlideRecord("problem");
            prob.category = current.category;
            prob.sub_category = current.subcategory; 
            prob.impact = current.impact;
            prob.urgency = current.urgency;
            prob.priority = current.priority;
            prob.assignment_group = current.assignment_group;
            prob.short_description = current.short_description;
            prob.description = current.description;
            prob.cmdb_ci = current.cmdb_ci;
            prob.u_business_service = current.u_business_service;
            prob.priority = current.priority;
        var sysID = prob.insert();
        current.problem_id = sysID;
        var mySysID = current.update();
        gs.addInfoMessage("Problem " + prob.number + " created");
        • Mark Stanger February 19, 2013 at 9:37 pm

          That’s great! I’m glad you got it working.

        • Michael February 27, 2023 at 2:58 am

          your tip was the only way I got it to work.

          i.e. putting the submit after the client confirmation.
          putting the submit in the backend code would invoke the submit even upon opening the record, already, which is too early and “uncontrolled”

  16. Andreas November 8, 2013 at 8:16 am


    just a heads up for everyone:
    There is a short version available for



    Instead of using

    gsftSubmit(null, g_form.getFormElement(), 'create_problem');

    you can also use



    There is only one issue one could trip over: It only works when the UI Action is a form button. When one is using a form link or form context menu type, the

    gel('<action name>')

    portion is not working.

    But I also have a question:
    Are the any other differences or known issues than the one I outlined above?

  17. Harisharan November 18, 2013 at 5:51 am

    We are using a similar one for Cancel change request functionality, however this seems to be working intermittently, that is most of the times the cancellation happens as expected. But in some cases, state is not getting set to Cancelled though we get the configured message ‘Change Cancelled’. Also Active is changing to false. Any idea what could be causing this intermittent behavior?

    function cancelClient()
        var ans = confirm('Are you sure you wish to Cancel this Change? If cancelled, this record cannot be reused.');
        if(ans == false)
            return false;
            gsftSubmit(null, g_form.getFormElement(), 'cancel_change');
    if(typeof window == 'undefined')
    function cancelchange()
        current.state = '4';
        gs.addInfoMessage('Change Cancelled');
    • Mark Stanger November 18, 2013 at 6:06 am

      If it’s working most of the time, my guess is that you’ve got a business rule or some other script that is setting the state value to something different. I would review the business rules in the system (along with tickets that haven’t closed correctly) to see if there are any commonalities between them.

    • Andreas November 18, 2013 at 8:34 am

      Also make sure that the action name of your UI Action is not the same as the onClick function name.
      If both are the same you get some really funny and weird behavior. I always add a “_” to the action name – e.g.: cancel_change

      Looking at your script that seems to be fine (cancelClient vs cancel_change). But you are not cancelling the workflow unless your workflow is having a parallel loop which keeps checking for the state of the change request, which then ends the workflow once it is fulfilled and cancels all active tasks.

      Check here for some scripting ideas:

  18. Jörgen May 15, 2014 at 4:46 am

    Great explanation. Have just learned the same on the Scripting Cource, but we didn’t get this great explanation why and how it’s actually working.

    • Mark Stanger May 15, 2014 at 4:54 am

      You’re welcome, I’m glad you found it useful! I hope they’re still telling people in the course where they got the idea from :).

  19. Tony January 2, 2015 at 1:07 pm

    This is a great tutorial. However, is there a way to do this on Mobile? Because g_form.getFormElement() is a deprecated method.

    • Mark Stanger January 2, 2015 at 1:35 pm

      I’m not sure what the mobile UI does to reference the form, but you might be able to get away with simply hard-coding the form ID name in place of ‘g_form.getFormElement’ like this…

      gsftSubmit(null, ‘’, ‘‘);

      • Tony January 2, 2015 at 3:04 pm

        Thanks for the quick response Mark. Unfortunately it looks as though ServiceNow mobile does not support Onclick within ui actions, so it looks like I’m going to need to find an alternative solution all together.

  20. Brian August 7, 2015 at 9:47 am

    Hi Mark, this tutorial has helped me quite a bit. I was wondering though, are you aware if something has changed in Fuji to make it so the condition – if(typeof window == ‘undefined’) – will no longer get called? This appears to be occurring in my Dev instance after it was upgraded from Eureka.

    • Mark Stanger August 7, 2015 at 9:51 am

      Thank you Brian. There’s nothing that has changed in Fuji to cause the issue you’re seeing as far as I’m aware. The ServiceNow demo systems ship with this kind of code in the standard ‘Resolve Incident’ UI action and it works just fine there.

      • Brian August 10, 2015 at 7:23 am

        Thanks for the quick reply and pointing me in the right direction. I wasn’t quite sure how to tell if the function was getting called properly or not. Turns out the issue was that my UI Action’s “Action Name” had the same name as another UI action. Which for some reason wasn’t a problem in Eureka, but I’m glad they have that standard now.

  21. MaC November 13, 2015 at 12:27 am

    Excellent work. It works like charm but for my situation ServiceNow glitch comes in i have below situation.
    We have Form A, where we have new button to open new form which take it to anther form where user fills data multiple times and we wanted to implement Go Back Functionality.

    I tried to implement my scenario using work-around above it works perfect but if user have not entered any data into mandatory fields then click on Go Back button did not take to to the parent form.

    However i would like to share with you guys the solution for may be you or any one else face this situation.

    – I made GO Back button on the form
    – Enabled button as Client – as described in this page original post
    – paste this -> parent.history.back(); in onClick box

    no need to put any scripts in script box

    It worked like cheers now going back was so easy. :)

    And least but not last thanks to Servicenow guru who posted this page it gave me starting point to make a button client and server side.

  22. William December 8, 2015 at 12:36 pm

    I’m a new ServiceNow admin and I’m definitely going to make sure tell people about this site! Thank you for your help, first off.

    Is the below code referencing a business rule? Does there have to be an accompanying business rule called “runBusRuleCode”?

    One of the biggest challenges I am having right now is the interconnectedness between client and server components. UI Actions and business rules, client scripts, and script includes, etc. How do all of these pieces fit together? And, where do I put this function reference in this other piece of ServiceNow.

    //Server-side function
    function runBusRuleCode(){
    current. = ;
    gs.addInfoMessage(‘You did it!’);

    • Mark Stanger December 8, 2015 at 2:00 pm

      @William, the purpose of this solution is to avoid having to have a separate UI action, client script, and/or business rule. The entire piece of code from this solution should go in the UI action ‘Script’ field. The call to the ‘runBusRuleCode’ function is made within the UI action Script itself.

  23. Christophe Silva December 10, 2015 at 8:05 am

    Hello, is it possible to use implement somthing ismilar, with glidedialogwindow on a ui action (for example: cancel) and after in the ui page a client script like the following:

    function prCancel(){

    GlideDialogWindow.get().destroy(); //Close the dialog window
    reloadWindow(window); //Refresh the form


    function cancelprocess(){

    current.state = 13;
    current.stage = ‘Request Cancelled’;

    var osmq_tsk = new GlideRecord(‘u_osmq_task’);
    osmq_tsk.addQuery(‘parent’, current.sys_id);

    while ( {
    osmq_tsk.work_notes = “Request item ” + current.number + ” was cancelled by associate. Please, Cancel task in OSMQ.”;


    • Mark Stanger December 12, 2015 at 6:05 am

      It’s not because once the UI action is clicked it’s done. The dialog would then be running on its own and wouldn’t have anything to do with the UI action that called it. You would want to set up your UI page with the necessary back-end code included in ‘cancelProcess’ instead. That’s a bit more complex to explain the specifics of, but that’s where it would need to be initiated from.

  24. William December 10, 2015 at 10:22 am

    I am taking advantage of your client & server code in one UI action but am running into issues yet again. Now when I launch the form it just closes immediately. Is there something in the code below that would cause it to do that?

    //Client-side ‘onclick’ function
    function newCredentialForm(){
    var tableName = g_form.getTableName();
    var sysID = g_form.getUniqueValue();

    //Call the UI Action and skip the ‘onclick’ function
    gsftSubmit(null, g_form.getFormElement(), ‘newCredentialForm’); //MUST call the ‘Action name’ set in this UI Action
    //Create and open the dialog form
    var dialog = new GlideDialogForm(‘Create Temporary Credential’, ‘u_temp_credential’); //callbackFunct no longer necessary
    dialog.setSysID(-1); //Pass in sys_id to edit existing record, -1 to create new record
    dialog.addParm(‘sysparm_view’, ‘credential_view’); //Use the Credential view of the form
    dialog.addParm(‘sysparm_form_only’, ‘true’); //Remove related lists
    dialog.render();//Open the dialog window

    //Get the values from the Incident Table so we can write-back to it. Done in server side code now.
    var comments = g_form.getValue(‘comments’);
    var short_description = g_form.getValue(‘short_description’);
    var work_notes = g_form.getValue(‘work_notes’);

    //Code that runs without ‘onclick’. Ensures call to server-side function with no browser errors
    if(typeof window == ‘undefined’)


    //Server-side function – not a business rule
    function runServer_SideCode(){

    //returning data from the temp cred form
    var obj = {};
    obj.application = current.u_application;
    obj.username = curent.u_for_user.user_name; //u_temp_credential.u_for_user => sys_user (table).user_name (userID field)
    obj.password = current.u_temp_password;

    //testing the dot walking for the username

    var utils = new CatalogUTILS();
    var uri = utils.setTempCredential(current.caller_id,obj.application,obj.username,obj.password,current.sys_id);

    current.comments = ‘to access your new credentials blah blah blah https://‘ + gs.getProperty(‘instance_name’) + uri;
    gs.addInfoMessage(‘You did it, scripting super-star!’);

    • Samiul April 11, 2016 at 7:54 pm

      Hi William,

      Did you manage to get any result after running your script?
      I noticed that you are trying to run ‘alert’ in server-side, i,e alert(obj.username); alert is run in the client side – you need to use gs.addInfoMessage(obj.username) to get the output.


  25. Ashish Nahar April 23, 2017 at 4:31 am

    Does this works even for a mobile UI action

    • Mark Stanger April 24, 2017 at 9:03 am

      No. Mobile UI is severely limited in regards to scripting support.

  26. Jennifer April 26, 2017 at 8:34 am

    Hi Mark, I have attempted to use the script provided but it is not working for us, in fact button is no longer showing anymore. I am new to scripting so I think that is the issue for me. Purpose is we have created a new type of task (RDTASK) and the users want a Close Task button in the header. Upon closure there are 5 fields that need to be mandatory before task can be closed. Right now I just have one in the code as I am just trying to get that to work. I am at a loss on how to make this work and would love for some assistance.

    • Mark Stanger April 26, 2017 at 11:49 am

      Hi Jennifer. Questions like these are probably best asked on the ServiceNow community site. Having said that, your button isn’t appearing because the ‘Condition’ value you have can’t ever evaluate to true (which displays the button).

      A condition of ‘current.state == 3 && current.state == 4’ is impossible since the state can’t be both 3 and 4 at the same time. I think instead of ‘and’ you want an ‘or’. Something like this for your condition should work better.

      current.state == 3 || current.state == 4

  27. MG November 9, 2017 at 3:02 pm

    Does this leave the server script open for user manipulation at that point, since it’s now on the client side? Or is the server-version of the code only called on the server side when the button is clicked?

  28. Justin January 4, 2018 at 9:28 am

    Worked perfectly! Thank you, Mark, for providing such great solutions to common problems. Keep up the great work!

  29. Sandeep December 5, 2018 at 1:58 pm

    Hi All,

    How to make this work on a UI action on related list ? I know that it says explicitly in the beginning that it is for only ‘Form button/Form Context Menu/Form Link’.

    I want users to be able to only select one of the related list records, and show them an alert when they select multiple and hit UI action.

    Client side of UI action : works fine, and counts the number of records selected and displays alert.
    Server Side : loses track of the ‘current’ record it was working on.
    After gsftsubmit, record of the main form ( on which related list was) becomes the current record.

    Anyone knows a way around that ?

  30. Rajneesh Pandey April 23, 2019 at 1:22 am

    its really good to see this article. i have been looking for this action. thank you

Comments are closed.




Fresh Content
Direct to Your Inbox

Just add your email and hit subscribe to stay informed.