- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-22-2018 11:12 AM
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>
Solved! Go to Solution.
- Labels:
-
Scripting and Coding
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-23-2018 11:25 AM
Hi Zhen,
There two issues here:
- 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).
- 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:
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-23-2018 11:25 AM
Hi Zhen,
There two issues here:
- 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).
- 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:
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-25-2018 06:18 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
01-28-2020 07:51 AM
This is amazing. Any idea how I could get this to work based off of user's preference using an interactive filter? I would like to use this on a dashboard with other reports, but I cannot seem to get this to respond to the other filter, nor can I make any of my other reports follow this filter.
Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
01-30-2020 03:58 AM
Hi
Have you tried this: https://docs.servicenow.com/bundle/orlando-performance-analytics-and-reporting/page/use/dashboards/t...