The CreatorCon Call for Content is officially open! Get started here.

Approval Widget Cancel button change status and add comment to work note

BenjaminY
Tera Contributor

I'm currently working on extending a custom approval widget in ServiceNow to include a "Cancel" button alongside the existing "Approve" and "Reject" options.

The goal is:

  • When a user selects Cancel, a comment is required.

  • Upon submission, the widget should:

    • Update the record_status field on custom table (on both the approval and related custom task record) to 'cancelled'.

    • Add the user's comment as a work note on the related custom task record (e.g., x_g_dh5_ccht_ccht_task).

      The reject button is changing the status to the record but not adding the comment once submitted.

      HTML:

      <div class="panel panel-{{::c.options.color}} b">
        <div class="panel-heading">
          <h4 class="panel-title" ng-if="c.data.state == 'requested'">${This {{c.data.label}} requires your approval}</h4>
          <h4 class="panel-title" ng-if="c.data.state == 'approved'">${Approved} <sn-time-ago timestamp="::c.data.sys_updated_on" /></h4>
          <h4 class="panel-title" ng-if="c.data.state == 'rejected'">${Rejected} <sn-time-ago timestamp="::c.data.sys_updated_on" /></h4>
          <h4 class="panel-title" ng-if="c.data.state == 'cancelled'">${Cancelled} <sn-time-ago timestamp="::c.data.sys_updated_on" /></h4>
       
        </div>  
        <div class="panel-body">
          <form ng-submit="$event.preventDefault()" class="form-horizontal">
            <div ng-if="c.data.fields.length > 0">
              <div ng-repeat="field in c.data.fields" class="m-b-xs" ng-if="field.value">
                <label class="m-n">{{field.label}}</label>
                <span ng-switch="field.type">
                  <div ng-switch-when="glide_date_time" title="{{field.display_value}}"><sn-time-ago timestamp="::field.value" /></div>
                  <div ng-switch-default >{{field.display_value}}</div>
                </span>
              </div>
            </div>
            <div ng-if="c.data.state == 'requested'" class="question">
              <button type="button" name="approve" class="btn btn-success btn-question" ng-click="c.action('approved')">${Approve}</button>
              <div class="spacer"></div>
              <button type="button" class="btn btn-default btn-question" ng-click="c.openModal('rejected')">${Reject}</button>
      <div style="height: 20px;"></div>
        <button type="button" class="btn btn-default btn-question" ng-click="c.openModal('cancelled')">${Cancel Request}</button>
        </div>
          </form>
        </div>  
      </div>
       
      <!--Setting Window for Comments JWD -->
      <script type="text/ng-template" id="modalTemplate">
        <div class="panel panel-default">
          <div class="panel-body">
            <div class="form-group">
              <label>
                {{ c.modalAction === 'cancelled' ? 'Justification for Cancelling Request' : 'Comments required when rejecting' }}
              </label>
              <input class="form-control" ng-model="c.data.comments" required />
            </div>
            <div class="form-group">
              <button 
                ng-disabled="!c.data.comments" 
                class="btn btn-primary btn-sm" 
                ng-click="c.action(c.modalAction); c.closeModal();">
                ${Submit}
              </button>
            </div>
            <div class="panel-footer text-right">
              <button class="btn btn-default" ng-click="c.closeModal()">Cancel</button>
            </div>
          </div>
        </div>
      </script>

      Client Script:
      function ($scope, $uibModal) {
      var c = this;
      c.data.comments = "";
      c.action = function(state) {
      c.data.op = state;
      c.data.state = state;
      c.server.update();
      }
      //Opens the pop-up for comments. JWD
      c.openModal = function(actionType) {
      c.modalAction = actionType; // either 'cancelled' or 'rejected'
      c.modalInstance = $uibModal.open({
      templateUrl: 'modalTemplate',
      scope: $scope
      });
      }
       
      c.closeModal = function() {
      c.modalInstance.close();
      }
       
      }

      Server Script:

      var gr = $sp.getRecord();
      if (input && input.op && gr) {
      gs.info("[WIDGET] Received comments: " + input.comments);
      gs.info("[WIDGET] Updating approval record: " + gr.getTableName() + " | " + gr.getUniqueValue());

      gr.comments = input.comments;
      gr.state = input.op;
      gr.update();

      // Update related task (x_g_dh5_ccht_ccht_task)
      var targetRecord = getRecordBeingApproved(gr);
      gs.info("[WIDGET] Related task record: " + (targetRecord ? targetRecord.getUniqueValue() : 'No related record'));

      if (targetRecord && targetRecord.isValidRecord()) {
      gs.info("[WIDGET] Updating related task record: " + targetRecord.getTableName() + " | " + targetRecord.getUniqueValue());
      targetRecord.setValue('state', input.op);

      // Check if work_notes field is valid and update it
      if (targetRecord.isValidField('work_notes')) {
      targetRecord.setValue('work_notes', input.comments); // Set comments in work_notes
      } else {
      gs.info("[WIDGET] work_notes field is not valid on related task record.");
      }

      targetRecord.update();
      } else {
      gs.info("[WIDGET] No valid related task record found or not accessible.");
      }
      }

      var fields = $sp.getFields(gr, 'state,sys_created_on');
      if (gr) {
      if (gr.sys_mod_count > 0)
      fields.push($sp.getField(gr, 'sys_updated_on'));

      data.fields = fields;
      data.state = gr.state.toString();
      data.sys_updated_on = gr.sys_updated_on.toString();
      data.sys_id = gr.getUniqueValue();
      data.table = gr.getTableName();

      var related = getRecordBeingApproved(gr);
      if (related && related.isValidRecord()) {
      data.label = related.getLabel();
      } else {
      data.label = gr.getLabel();
      }
      }

      function getRecordBeingApproved(gr) {
      if (!gr.sysapproval.nil()) return gr.sysapproval.getRefRecord();
      return gr.document_id.getRefRecord();
      }



      BenjaminY_0-1747074522223.pngBenjaminY_1-1747074625983.pngBenjaminY_2-1747074706495.png

       

 

3 REPLIES 3

Rajat Gupta6
Tera Guru

try 

gr.comments.setJournalEntry(input.comments.toString());

 

Please accept my solution if it works for you and thumps up.

This seems to only work within global applications

Rajat Gupta6
Tera Guru

Then gr.comments = input.comments.toString(); should work fine for scoped apps.