Related SC Tasks to RITM - Conditions and Loops for Service Portal widget

Adam Wencel
Giga Contributor

Hi Admin Community,

I'm not an expert in Angular JS nor even JS, but I have a long background of learning on the fly and adapting to anything that comes my way as an IT professional.  My post here is both one of a question about my configuration as well as I'm open to adjusting my approach.

I'm trying to achieve displaying the SC task information into the standard ticket tab by using the custom tab type as mentioned here - https://docs.servicenow.com/bundle/rome-servicenow-platform/page/build/service-portal/task/configure-st-page.html.  See below.

find_real_file.png

Here is a snippet of the HTML that is showing this (which is also part of the widget I mention below):

iv>
      <div role="row" class="list-group-item table-responsive" ng-repeat="item in c.data.request.req_list" style="margin:0px" >
        <div role="cell" class="col-xs-2 padder-l-none padder-r-none main-column">
          <div class="primary-display">
            <a href="?id={{::item.url.id}}&table={{::item.url.table}}&sys_id={{::item.url.sys_id}}" sn-focus="{{::item.highlight}}"> {{::item.display_field}} </a>
          </div>
          <small class="text-muted">
            <div ng-repeat="f in item.secondary_displays" class="secondary-display">
              <span >{{::f.display_value}}</span>
            </div>
          </small>
        </div>
        <div role="cell" class="col-xs-4 padder-l-none padder-r-none shortdescription-column">
          <div class="state">
            <span>{{::item.shortdescription}}</span>
          </div>
        </div>
        <div role="cell" class="col-xs-2 padder-l-none padder-r-none state-column">
          <div class="state">
            <span>{{::item.state}}</span>
          </div>
        </div>
        <div role="cell" class="col-xs-2 padder-l-none padder-r-none created-column">
          <div class="created">
             <i class="fa fa-clock-o" aria-hidden="true" title="${Created}"></i>
            <sn-time-ago timestamp="::item.created"/>
          </div>
        </div>
        <div role="cell" class="col-xs-2 padder-l-none padder-r-none updated-column">
          <div class="updated">
            <i class="fa fa-clock-o" aria-hidden="true" title="${Updated}"></i>
            <sn-time-ago timestamp="::item.updated_on"/>
          </div>
        </div>

The widget that I'm embedding in the tab area is the My Request widget.  I like the use of it since it gives me the ability to adjust the information presented using both scripting (if desired) as well as the Standard Ticket Configuration on the backend.  So, it's very versatile for me at the moment while I continue to learn JS and AngularJS as one of the admins of this tool.  The widget screenshot as well is just a dump (with a display limiter on it) of all SC task information related to myself (ie My Requests).

I know that you cannot call the parent.sys_id of the SC task here just by using the current instance of the serverside scripting since the code is isolated in the widget itself.  However, I do know that you can use a scope call to bring in the current sys_id of the RITM and hold that as a variable.  What I don't know is below, and I'm hoping someone can either help me or guide me in the right direction here.

  1. Do I control the while loop of gr.next() with a condition (scoped sys_id) on the Serverside script of the widget?
  2. Do I control the NG-Repeat of the HTML with a condition (scoped sys_id or anything else) on the Angular side of the HTML portion of the widget?
  3. Should I take another direction with a condition to display this information?

Again, I'm open to feedback on this and want to understand what is correct in my assumption and what clearly is not.

1 ACCEPTED SOLUTION

Hi all,

I have definitely solved my initial request to gain only related SC tasks to the RITM using the suggested direction from @palanikumar .  Please see below how I solved it ultimately, and I'll try to keep it separated properly.

This is very specific to a widget embedded inside another widget where calling the parent sys_id is NULL by default and design.

Steps

Variable Work

I had to ensure the scoped RITM sys_id for the instance was stored in a variable.

var sys_id = (input && input.sys_id) || options.sys_id || $sp.getParameter("sys_id");
var sysId = options.sys_id || $sp.getParameter('sys_id');

Serverside Scripting

What I had to do was leave the original taskIDs alone in the "My Requests" widget and actually add another line as Palani may have hinted beforehand.

gr.addQuery('parent.sys_id=' + sysId);

This isolated (when specifically filtering out SC tasks) related records of the parent sys_id using the scoped values in the variable.

Caveats

Users by default do not have privilege to access and read/write to the sc_task table via roles.  I will have to research how to enable that by ACL to role if ServiceNow allows that.

 

Hopefully this helps a lone soul like myself who isn't a developer by trade.

View solution in original post

16 REPLIES 16

palanikumar
Mega Sage

Hi,

I suggest you to add your condition in the Server side. I hope your code is using GliderRecord for querying the table. You can add gr.addQuery to add your condition. Refer the below URL for more details on GlideRecord

https://developer.servicenow.com/dev.do#!/learn/learning-plans/quebec/new_to_servicenow/app_store_le...

Thank you,

Palani

Thank you,
Palani

Hi @palanikumar ,

I have done this before via the gr.addQuery to add the condition to the gr.next(), however, it only pulls the RITM value since I specifically call and hold only that value.  See below.

var sys_id = (input && input.sys_id) || options.sys_id || $sp.getParameter("sys_id");
var sysId = options.sys_id || $sp.getParameter('sys_id');
gr.addQuery('sys_id', sysId);

My issue is that while using gr.next(), the sysId variable will now only represent the RITM link and just one line.  This is the while loop where I think you need me to place the condition.

while (recordIdx != data.lastLimit && gr.next()) {
		
		var portalSettings = myRequestMap[gr.getUniqueValue()];
		if (typeof portalSettings == 'undefined')
			portalSettings = {};

		var record = {};
		record.sys_id = gr.getValue('sys_id');

		if (gr.getRecordClassName() == 'sc_request') {
				var ritm = new GlideRecord("sc_req_item");
				ritm.addQuery("request", gr.getUniqueValue());
				ritm.query();
				if (ritm.getRowCount() == 0)
					continue;
				if (ritm.getRowCount() > 1)
					record.display_field = gs.getMessage("{0} requested items", ritm.getRowCount());
				else {
					ritm.next();
					record.display_field = ritm.cat_item.getDisplayValue() || ritm.getDisplayValue("short_description");
					var sctask = new GlideRecord("sc_task");
					sctask.addQuery("request_item", ritm.getDisplayValue());
					sctask.query();
				if (sctask.next())
					record.sc_task_id = sctask.getDisplayValue('number'); 
				}
				record.url = { id: portalSettings.page? portalSettings.page: 'sc_request', table: 'sc_request', sys_id: record.sys_id};
		}  else {
				record.display_field = portalSettings.primary_display ? getField(gr, portalSettings.primary_display).display_value : getField(gr, 'number').display_value;
				record.url = { id: portalSettings.page? portalSettings.page :'ticket', table: gr.getRecordClassName(), sys_id: record.sys_id};
		} 
		if (portalSettings.secondary_displays) {
			record.secondary_displays = [];
			portalSettings.secondary_displays.split(",").forEach(function (sDisplay){
				record.secondary_displays.push(getField(gr, sDisplay));
			});
		}
		else 
			record.secondary_displays = getField(gr, 'short_description');
		record.shortdescription = gr.getValue('short_description');
		record.updated_on = gr.getValue('sys_updated_on');
		record.created = gr.getValue('sys_created_on');
		record.state = gr.getDisplayValue('state');

		if((recordIdx !== 0) && (data.lastLimit - limit === recordIdx))
			record.highlight = true;
		
		data.request.req_list.push(record);
		recordIdx++;
		
	}

I'm not an expert in this, so bear with me.  I know that for the conditions (if/else) here that else is normally chosen based on how I've configured it.  If you had to toss a condition here to control that then please let me know.  If we're concentrating on the serverside scripting path, this is the area that I'm not strong in and need the guidance.

I believe you might be right on this.  I will post a response and mark as correct once I validate this item.

Hi all,

I have definitely solved my initial request to gain only related SC tasks to the RITM using the suggested direction from @palanikumar .  Please see below how I solved it ultimately, and I'll try to keep it separated properly.

This is very specific to a widget embedded inside another widget where calling the parent sys_id is NULL by default and design.

Steps

Variable Work

I had to ensure the scoped RITM sys_id for the instance was stored in a variable.

var sys_id = (input && input.sys_id) || options.sys_id || $sp.getParameter("sys_id");
var sysId = options.sys_id || $sp.getParameter('sys_id');

Serverside Scripting

What I had to do was leave the original taskIDs alone in the "My Requests" widget and actually add another line as Palani may have hinted beforehand.

gr.addQuery('parent.sys_id=' + sysId);

This isolated (when specifically filtering out SC tasks) related records of the parent sys_id using the scoped values in the variable.

Caveats

Users by default do not have privilege to access and read/write to the sc_task table via roles.  I will have to research how to enable that by ACL to role if ServiceNow allows that.

 

Hopefully this helps a lone soul like myself who isn't a developer by trade.