How to dynamically update content block based on selected option using Jelly?

zhen
Kilo Explorer

Hi there!

I am trying to write a script that will update the content in a dynamic content block based on the option selected.  The option should query back to a table and look for results related to the table.  I am getting stuck on the onchange function...

 

<g:evaluate var="jvar_tasktypes" object="true" jelly="true">
var tables = 'u_billing_information';
var obj=[];
var gr= new GlideAggregate('u_billing_information');
  gr.groupBy('u_business_unit');
  gr.query();
  while(gr.next()){
    obj.push([gr.getValue('u_business_unit'),gr.getDisplayValue('u_business_unit')]);
  }
  obj;
</g:evaluate>

 <select id='filter_task_type' class='select2-search' onchange='filterTaskType()'>
        <option value="">All</option>
        <j:forEach var="jvar_tasktype" items="${jvar_tasktypes}">
            <option value="${jvar_tasktype[0]}">${jvar_tasktype[1]}</option>       
        </j:forEach>
    </select>  
<script>
function filterTaskType(){
 var taskType = $j('#filter_task_type').val();
<g:evaluate var="jvar_gr" object="true">
   var gr = new GlideRecord("u_billing_information");
   gr.addQuery('u_business_unit', taskType);
   gr.query();
   gr;
</g:evaluate>
<j:if test="${jvar_gr.next()}">
   hello I see you
</j:if>

}

</script>

 

 

1 ACCEPTED SOLUTION

ChrisBurks
Mega Sage

Hi Zhen,

 

There two issues here:

  1. Jelly processes server side before the page is rendered. Therefore making a change to the select drop down won't trigger anything unless there is some sort of page refresh and "caching" of the data to pass (many times done via url params in ServiceNow). 
  2. Even if it were able to pass the data directly, the filterTaskType function still wouldn't display because there is no return of the data because the j:if statement is still inside the function. 

There are a few ways to resolve this. One popular way is to use a combination of a Client Callable Script Include and a GlideAjax call to that script include. Important Note: Script Include must be Client Callable. That's accomplished by checking that field on the Script Include form when creating it.

 

Example:

Note: This is based on your posted script. However, some things are modified because I don't have the same environment, such as tables, as you. The concepts are still the same.

Client Callable Script Include:

var BillingInfoUtil = Class.create();
BillingInfoUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	
	getBillingInfo: function(){
		var taskType = this.getParameter('sysparm_task_type');
		gs.log("Task Type: " + taskType, "Select EX")
		var gr = new GlideRecord("incident");
		//this gliderecord setup is assuming you're expecting one record exists that meets the
		//criteria. Adjust if necessary
		gr.get(taskType);
		var fields = ['number','short_description','state']
        var bu = {};
		if (gr.getUniqueValue()){
			//this is an assumption. You'll need to determine what your needs are;
			fields.forEach(function(field){
				bu[field] = gr.getValue(field)
			})
			
		}
		
		return JSON.stringify([bu]);
		
	},

    type: 'BillingInfoUtil'
});

 

Dynamic Content Block using GlideAjax:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
	<g:evaluate var="jvar_tasktypes" object="true" jelly="true">
		// Changed to GlideRecord for demo purpose as I don't have the same tables or setup as you
		var objs = [];
		var gr= new GlideRecord('incident');
		gr.groupBy('number');
		gr.setLimit(5);
		gr.query();
		while(gr.next()){
		objs.push({'sys_id': gr.getValue('sys_id'),'number':gr.getDisplayValue('number')});
		}
		objs;
	</g:evaluate>
	<div class="container">
		<div class="col-md-3">
			<div class="panel-body">
				<h4>Select an Incident</h4>
				<select id='filter_task_type' class='select2-search form-control'  onchange='filterTaskType()'>
					<option value="">All</option>
					<j:forEach var="jvar_tasktype" items="${jvar_tasktypes}">
						<option value="${jvar_tasktype.sys_id}">${jvar_tasktype.number}</option>       
					</j:forEach>
				</select>  
			</div>
		</div>
		<div class="col-md-9">
			<div class="panel-body">
				<h3>Incident Details</h3>
				<div id="incDetails">
					<div class="list-group"></div>
				</div>
			</div>
		</div>
	</div>
	<script>
		function filterTaskType(){
			var container = document.querySelector('.container');
			var taskType = container.querySelector('#filter_task_type').value;
		    var incDetails = container.querySelector('.list-group');
			
		  //Here is where the GlideAjax comes in instead of g:evaluate
		    var ga = new GlideAjax('BillingInfoUtil');
			ga.addParam('sysparm_name', 'getBillingInfo');
			ga.addParam('sysparm_task_type', taskType);
			ga.getXML(callback);
			
			function callback(response) {
			  var result = response.responseXML.documentElement.getAttribute("answer");
		      var details = JSON.parse(result);
		      var keys = Object.keys(details[0]);
		      var html = [];
		      keys.forEach(function(key){
				 var label = key.toUpperCase().replace("_", " ");
		         var text = details[0][key];
		         html.push('<div class="list-group-item"><h4 class="list-group-item-heading">'+ label + '</h4>');
				 html.push('<p class="list-group-item-text">' + text + '</p></div>');
			  });
		       incDetails.innerHTML = html.join("");
			  
			}

		}

	</script>

</j:jelly>

 

Screencast of result:

View solution in original post

11 REPLIES 11

Hi @ChrisBurks 

Came across your solution above which I think will be useful to users.

I don't do scripting so this is totally new to me. I am not admin in workplace but I have my Rome development instance.

I have copied the code in your Client Callable Script Include: section and pasted into System Definition>Client scripts>New. Is this correct? I get an error object gs should not be used in client script.

find_real_file.png

I have added a dynamic content block widget to a new dashboard and then pasted in the code in your Dynamic Content Block using GlideAjax: section.

find_real_file.png

I then have the option to select 5 incidents but when I select one the number, short description and state results are not returned.

find_real_file.png

Advice would be appreciated.

Thanks

Hi @jasonedwards ,

The Client Script that you have in your screenshot is not the same as a Client Callable Script.
A Client Callable script is a Script Include with the Client Callable field checked so that it can be called client side via a GlideAjax call.

Script Includes: https://docs.servicenow.com/bundle/rome-application-development/page/script/server-scripting/concept/c_ScriptIncludes.html

 

GlideAjax: https://docs.servicenow.com/bundle/rome-application-development/page/app-store/dev_portal/API_reference/GlideAjax/concept/c_GlideAjaxAPI.html

 

@ChrisBurks 

Thanks for replying and your guidance. Selected the correct script include this time and is now working 🙂 Cheersfind_real_file.png

Hey ,Thanks for providing such a helpful content but i need your help to understand why mine output html is not rendered properly ,in-fact when i select the incident number right side o/p side showing blank.

AyanshN_0-1741336687110.png

Help me in that to understand the exact problem.

Hi @AyanshN 

 

If you could post what you have setup like the html and the code, community or I could help a lot more. Otherwise we would only be guessing at what the issue could be.