Jelly Script: how to display List field entries in a line-per-line format

tahnalos
Kilo Sage

I have two different List fields, one reference and one not on my UI Page. The Reference one is a list of people impacted by an Incident.  Right now, the UI page is displaying this:

 

<example 1>

Impacted Users: Walter White,Jesse Pinkman,Gustavo Fring,Saul Goodman,Lalo Salamanca

 

We want to have the UI page to display things like this:

 

<example 2>

Impacted Users:
Walter White
Jesse Pinkman
Gustavo Fring
Saul Goodman
Lalo Salamanca

 

However, we may want to display this as a Table entry as we would like to eventually expand things to include the user's support group like below:

 

<example 3>
Impacted Users:
Walter White          Heisenberg Inc
Jesse Pinkman        Heisenberg Inc
Gustavo Fring         Los Pollos Hermanos
Saul Goodman        Saul Goodman and Associates
Lalo Salamanca       El Michoacano

 

Any help would be appreciated.

1 ACCEPTED SOLUTION

Rather than building a string of your HTML in JavaScript code nested within an evaluate tag, you can use Jelly to build your markup.

The idea is to first use <g:evaluate> to grab the data you want to be included in your output HTML and store that in some sort of data structure. The g:evaluate part of your script can essentially be the "preprocessing" part, which is responsible for obtaining some sort of data that you want to display. That data can then be looped over using a <j:forEach> to build your HTML <table>

 

For example:

 

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
      <!-- Add your first <g:evaluate> here but change it to a <g2:evaluate> --->

	<g2:evaluate jelly="true">
		var stakeList = jelly.jvar_incidentgr.u_impacted_user_list.getDisplayValue().split(', ');
	</g2:evaluate>
	<p>Names</p>
	<table>
		<tbody>
		<j2:forEach var="jvar_impactedUser" items="$[stakeList]">
			<tr>
				<td>$[jvar_impactedUser]</td>
			</tr>
		</j2:forEach>
		</tbody>
	</table>
</j:jelly>

 

You can make the stakeList array hold more sophisticated data, such as objects to hold related data. You can then add additional columns to each row (<tr>) in your table by adding an additional <td> to output any other associated data. You can refer to MDN's article on styling tables if you want to add additional cellpadding/spacing or a border. 

 

In the above example, I'm using a g2:evalaute as it will recompute the HTML each time the UI page is loaded, as opposed to a g:evaluate that caches the rendered HTML output and doesn't update it on subsequent reloads. It's up to you decide which is best for you, but if you're using g2/j2, then you need to use $[] instead of ${} when accessing variables. 

 

In addition, I suggest checking out Chuck Tomasi's YouTube guide on Jelly scripting, the links can be found at the top of the Jelly Scripting documentation in the ServiceNow docs.

View solution in original post

9 REPLIES 9

So I tried something similar to your approach but I can't seem to be getting the values of this below code block to work.  When I tried to output jvar_affectedLobList and jvar_affectedServicesList, it showed that there is nothing in the array.  Am I doing this right?

 

	<g:evaluate var="jvar_incidentgr" jelly="true" object="true">
		var incidentGr = new GlideRecord('incident');
		incidentGr.get(RP.getParameterValue('sysparm_sys_id'));
		incidentGr;
	</g:evaluate>

	<g:evaluate var="jvar_affectedLobList" jelly="true" object="true">
		var lobList = jelly.jvar_incidentgr.u_affected_lob.getDisplayValue ().split (', ');
		lobList;
	</g:evaluate>
	
	<g:evaluate var="jvar_affectedServicesList" jelly="true" object="true">
		var serviceList = [];
		var ici = new GlideRecord ('task_cmdb_ci_service');
		ici.addQuery ('task', jelly.jvar_incidentgr);
		ici.query ();
		
		while (ici.next ())
		{
			serviceList.push (ici.cmdb_ci_service.name.toString ());
		}
		serviceList;
	</g:evaluate>


	<j:if test ="${jvar_affectedLobList.length > 0 || jvar_affectedServicesList.length > 0}">
		<div class="info-panel">
			<table class="stakeholders">
				<tbody>
					<j:if test="${jvar_affectedLobList.length > 0}">
						<tr>
							<td style="width:40%"><b>${incidentGr.getElement ('u_affected_lob').getLabel ()}</b></td>
						</tr>
						<j:forEach var="jvar_affectedLob" items="${jvar_affectedLobList}">
							<tr>
								<td>${jvar_affectedLob}</td>
							</tr>
						</j:forEach>
					</j:if>
					<j:if test="${jvar_affectedServicesList.length > 0}">
						<tr>
							<td><b>Affected Services:</b></td>
						</tr>	
						<j:forEach var="jvar_affectedService" items="${jvar_affectedServicesList}">
							<tr>
								<td>${jvar_affectedService}</td>
							</tr>
						</j:forEach>
					</j:if>
				</tbody>
			</table>
		</div>
	</j:if>

 

Your code looks good to me, however, you may want to try changing:

ici.addQuery ('task', jelly.jvar_incidentgr);

to be:

ici.addQuery ('task', jelly.jvar_incidentgr.getUniqueValue());

Running your code with the above change in a globally scoped UI page works in my instance (substituting fields/records for OOTB fields that exist in my instance).  

If it still doesn't work, try hardcoding some values, such as replacing the RP.getParameterValue('sys_id') with a hardcoded sys_id of an incident to see if that's potentially causing issues. You can use gs.info() within your evaluate tags to help further debugging to see if you can spot something.

Could scoping be the issue?  The UI page is being created in its own application, not on Global.

Yes, Jelly scripts tend to (annoyingly) behave differently when in a scoped app vs global scope. I believe it's because you're trying to use JS syntax where a JEXL expression is expected, try using `empty()` to determine if an array is empty instead of `.length > 0`. Don't forget to also add the `.getUniqueValue()` call as suggested in my last reply:

 

 

 

<j:if test ="${!empty(jvar_affectedLobList) || !empty(jvar_affectedServicesList)}">
		<div class="info-panel">
			<table class="stakeholders">
				<tbody>
					<j:if test="${!empty(jvar_affectedLobList)}">
						<tr>
							<td style="width:40%"><b>${incidentGr.getElement ('u_affected_lob').getLabel ()}</b></td>
						</tr>
						<j:forEach var="jvar_affectedLob" items="${jvar_affectedLobList}">
							<tr>
								<td>${jvar_affectedLob}</td>
							</tr>
						</j:forEach>
					</j:if>
					<j:if test="${!empty(jvar_affectedServicesList)}">
						<tr>
							<td><b>Affected Services:</b></td>
						</tr>	
						<j:forEach var="jvar_affectedService" items="${jvar_affectedServicesList}">
							<tr>
								<td>${jvar_affectedService}</td>
							</tr>
						</j:forEach>
					</j:if>
				</tbody>
			</table>
		</div>
	</j:if>

 

 

 

Thanks, your tips actually helped me finish what I needed to do.  Cheers.