Create custom action buttons in Service Portal

A common feature request for Service Portal is to be able to add custom buttons to the sc_request or ticket page similar to the way you could add UI actions to a form. This functionality is not available out-of-box, but here is a quick example on how you could create a custom widget to display some buttons to mimic the UI Actions on a form.

In this example, we will create a “Resolve Incident” button to place on the incident “ticket” page.

HTML:

Client Script:

Server Script:

The resulting widget should look something like this:

screenshot-2016-12-01-10-16-53

This is far from the complete solution, but will hopefully provide a good example to work off of.

59 comments

  1. Hi Nathan,

    Thanks for this – it has helped a lot.

    Regarding the if action = resolved code block, what is the best way to address having a pop up box to confirm that you want to resolve the incident?

    I have tried the following, however I get an error when clicking the button

    // If Incident table
    if (data.table == ‘incident’) {
    if (action == ‘resolve’) {
    if(confirm(“Are you sure you want to Resolve this Incident?”)){
    // Resolve Incident
    gr.setValue(‘incident_state’, 6);
    gr.setValue(‘state’, 6);
    gr.setValue(‘resolved_by’, gs.getUserID());
    gr.update();
    }
    //If cancel abort
    return false;
    }

    The Error I receive is: Server JavaScript error “confirm” is not defined.

    Looking at that error – would I need to define confirm in the client script? If so – I am not too sure what to add?

    Cheers Nathan, just stumbled upon the blog and really liking it.

    Cheers,
    Brendan

    1. Hi Brendan, that’s because “confirm” is a client side method that is run in the browser so it’s not possible to execute from server script.

    2. Brendan,
      Add something like this to your Client Script

      function() {
      var c = this;
      c.uiAction = function(action) {
      if(action == ‘cancel’){
      var r = confirm(“Are you sure you want to cancel this request?”);
      if(r == false){
      return;
      }
      }
      c.data.action = action;
      c.server.update().then(function() {
      c.data.action = undefined;
      })
      }
      }

  2. Yes, must be client side:

    c.uiAction = function(action) {
    if(!confirm(“Are you sure?”)) return;
    c.data.action = action;
    c.server.update().then(function() {
    c.data.action = undefined;
    })
    }

  3. Thanks Nathan – this worked like a champ!

    Is there an easy way to make the buttons a specific color? As is the top button gets the same color as the top heading of the other widgets on the page. I’m sure it is just using the default style, but I don’t know where or how to override that.

    1. Hi Jeff,

      The button colors is getting the color from the “btn-primary” Bootstrap class which gets compiled based on the CSS variables you have defined. You can always change out the class for one of the other color classes (e.g. btn-success, btn-info) or create a custom class and style it in the CSS field on the widget. If you need help, shoot me an email and I can show you an example.

  4. Hi Nathan, thanks for the post, very handy indeed.

    I wanted to ask you what the difference is between using server.update() and server.get()? So for example, your code block in the controller would be something like:

    c.uiAction = function(action) {
    c.server.get({
    action: action
    }).then(function(response) {
    /…… /
    });
    };

    I’m trying to find any information on the difference, thanks again.

    1. Hi Nathan,

      I just replicated the code in my portal .

      The server update is not getting done i.e, the particular incident is not getting resolved , even though gs.info is getting logged in log statement.
      if(data.table == ‘incident’){
      if(action ==’resolve’){
      gs.info(‘inside resolve’ +action);
      //gr.setValue(‘incident_state’,6);
      gr.setValue(‘state’,6);

      Not able to understand what is the mistake i am doing

  5. Hi Nathan,

    Thanks for this – it’s great!

    I’m just wondering if there’s any way I can get it to only show if the state isn’t resolved or closed etc?
    Also, it would be great if it could update the Work Notes or Additional comments that the user has resolved it!

    Thanks

    Mithun

    1. This is just to be an example and up to you to finish. You can use ng-if on the button to hide when state not resolved. You can also easily add to the worknotes from the server script.

    2. Hi Mithun,
      I used the code above to create a ‘Reopen Incident’ button and have it show only if the state is resolved. I added ng-if=”data.showButton” to the HTML template.
      In the Server Script…
      if(data.table == ‘incident’ && gr.state == 6){
      data.showButton = true;
      } else {
      data.showButton = false;
      }
      Seems to be working well.

      1. Hi, can you post the code you used for this? I’m trying to do the same thing and made some edits, but I’m still having a bit of trouble.

      2. Hi Troy,

        Thanks for your code it works well in my implementation – just a note that might be handy, I worked with one of our web developers and he shortened this down to a single line which works really well, figured I’d share:

        data.showButton = gr.state == 6;

        Cheers
        Carl.

  6. I have a requirement to create close button . i used ng-hide to hide button when state closed but when i reload the form “Close” button again appearing . plz suggest a way if state is closed button is not visible

    1. That just means the expression in your ng-hide is not returning true. Double check the values and make sure they are correct and of the correct type. For example, sometimes what you think is a Boolean could be a String. But without seeing your code I cannot comment further.

    2. Hi Ankit,

      Did you figure this out? I have the same issue when reloading the form the button re-appears.

  7. Hi Nathan,

    I want a button which should send comments to the back end table. For example an approval widget I have created a comment text box and send button. When user wants any additional info user will add information in the comment field and hit on send button. then comments should passed to the approval form. Can you please help me on this.

    Thanks,
    DGP

    1. The concepts in this tutorial would work just the same for this use case… create a button, capture the info and send to the server using server.update, and then use GlideRecord to insert the data to the appropriate table.

  8. Hi Nathan,
    Thanks for code! Works slick. I created a ‘Reopen Incident’ button and was able to hide it if the inc state isn’t resolved. However, I need to require comments if they try to reopen the incident. I can’t seem figure out the code to look at the comments box and stop the reopening if there isn’t a comment.

    I’ve discovered g_form doesn’t work like it does on the ‘Reopen Incident’ in the incident form in the native view. Any help would be appreciated! Thanks.

    1. Hi Troy,

      This is exactly what I intend to do.

      Can you let me know how you implemented hiding the button when state is not resolved, I am new to Service Portal and hence I am asking this noob question

      Thanks,
      Urmilla

  9. What if I have a form widget and a custom button widget on same page. If I change any value to the form and click on button, it updates the form.

    What I m trying to achieve is to redirect on button click as well as save the form. As you know action.setRedirectURL() does not work with Service Portal, so I achieved it by changing some part of your code. But I am still trying to figure out how to update the form.

    Any views?

      1. Hi Nathan,

        Thanks for the reply.
        Is there any way I can call the out of the box event in form widget to update the record? I see below set of code which updates the form onclick of UI Action.

        $scope.$on(“spModel.uiActionComplete”, function(evt, response) {
        var sysID = (response.isInsert) ? response.sys_id : $scope.data.sys_id;
        loadForm($scope.data.table, sysID).then(constructResponseHandler(response));
        });

        My button widget has a glide object of the same table and record as the form, but when I try to pass it, it is still not updating the form. If I don’t pass any response it gives me a console error.

        $rootScope.$broadcast(“spModel.uiActionComplete”, c.data.gr);

        c.data.gr has the glide object from server script.

        data.table = input.table || $sp.getParameter(“table”);
        data.sys_id = input.sys_id || $sp.getParameter(“sys_id”);
        data.id = input.id || $sp.getParameter(“id”);

        // Valid GlideRecord
        var gr = new GlideRecord(data.table);
        if (!gr.isValid())
        return;

        // Valid sys_id
        if (!gr.get(data.sys_id))
        return;

        data.gr = gr;

        I also tried by getting the “g_form” broadcast from form widget to button widget and resend it back as the response. Still no luck.

        Thanks
        Karan

  10. HI All,

    How to add a button as”modify Approver?”(should refer to User table) in the catalog item form . Once added approver it should get reflected in the respect form.

    THanks

  11. Hi Nathan

    I have my html set to show / hide certain buttons:

    <button ng-if="data.state!=130 && data.state!=3"

    However, once I click the resolve button, the incident will resolve, my comments added etc, but the resolve button does not disappear until I refresh my browser..

    Any ideas?

    Thanks

  12. I created a button for cancel on the service portal using this site thank you it was so useful! I now tried to created a request approval button on the service portal which works exactly as i need it to, however the button visibilty should only show when on the change_request ticket form and seems to be coming up on incident as well, so i think I’m missing something because its not reading my visibility code. Also when i click request approval the button is not disappearing?

  13. Thanks for posting this – really useful.

    I’m trying to add a button to update a field in the HR Module (table=sn_hr_core_case) but when I reload my page where I have added the widget I receive a bunch of read errors at the top whic are:

    -Server Javascript error Cannot read property “table” from undefined
    -Line number 4
    -Script source code logged to browser console
    -failing widget: ‘Opus Reapproval’ (sys_id of my widget)

    Not sure why this isn’t working – is it because I’m in the ‘HR Service Portal’ scope?

    1. I have this working now – I made it more HR Case specific as opposed to a generic ‘table’ property.

  14. Hi,

    Worked with one of our internal web developers and he shortened the section int he server script, lines 16 to 32:

    if (input && input.action) {
    var action = input.action;

    // If Incident table
    if (data.table == ‘incident’) {
    if (action == ‘resolve’) {
    // Resolve Incident
    gr.setValue(‘incident_state’, 6);
    gr.setValue(‘state’, 6);
    gr.setValue(‘resolved_by’, gs.getUserID());
    gr.update();
    }
    if (action == ‘cancel’) {
    // Do something else
    }
    }
    }

    The new code looks like this:

    switch (input && input.action) {
    case ‘resolve’:
    gr.setValue(‘incident_state’, 6);
    gr.update();
    break;
    // case ‘cancel’:
    //do something else – keep adding case sections for more buttons…
    }

    Quite a lot shorter, hope this helps someone.

    Cheers
    Carl.

    1. You can use the ng-disabled=”shouldBeDisabled” directive in the button and decide when to make it true or false in you client controller

  15. Great article Nathan – many thanks.

    Can you give any advice regarding either re-sizing the button text according to size of the button, or preferably wrapping the button text if the button is too narrow to accommodate the text (at present the text will extend outside the button if the button width is too small).

    thanks again

  16. I want code hmtl and server and client script for creating registration form can anyone help me. Do it plz

  17. so what is the final code for HTML, Client Controller, and Server Script. Not sure I can follow all the chats. Can someone just add the final code for all? I am only looking to add a Reopen Incident button.

    1. Simply take the code from the post and change lines 24-26 to open the incident instead of resolving it.

  18. Hello ,

    I need the update button in the service portal for the incident table.
    When i click the update button then all the data inthe form form should update in the service portal.
    Can u please help for html,css, client,server code on widget.

  19. Hello All,

    I have implemented the code in my MSP Instance for one of our customer.But no luck,The code is not working as expected.Even when I click on Resolve Button its not working nor its resolving the Incident.
    Can anyone help me out here.

    Thanks

  20. Hi,
    Can we copy a existing RITM from portal to create new and user should be able to modify and submit new RITM from Portal page.

  21. Hi Nathan,

    I have one requirement , create “copy” button , on-click copies entire form and redirect to duplicate form along with the which we have filled values in variables on record producer form in service portal. Could you please help me on this

    These action should works before submit the form. Post creation of other form user would submit the both forms individually if required

Leave a Reply

Your email address will not be published. Required fields are marked *