HTML structure in Jelly Scripting
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
14 hours ago - last edited 14 hours ago
Hi
I am working on a requirement where i want to show/hide a UI formatter from on a UI macro based on the reference field on the form.
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<style>
tr:nth-child(even) {
background-color: #DCDCDC;
}
td,
th {
padding: 5px;
border: 1px solid black;
border-collapse: collapse;
}
table {
margin-left: auto;
margin-right: auto;
border: 1px solid black;
border-collapse: collapse;
}
</style>
<script>
function saveCostPlanData() {
var data = {};
// Get all inputs for carry_over (this gives us all years)
var carryInputs = document.querySelectorAll("input[id^='carry_over_']");
carryInputs.forEach(function(input) {
// Extract year from id → carry_over_FY25 → FY25
// var year = input.id.replace("carry_over_", "").toLowerCase();
var year = input.id.replace("carry_over_", "");
data[year] = {
carry_over: input.value || "",
supplemental: document.getElementById("supplemental_" + year)?.value || "",
release: document.getElementById("release_" + year)?.value || ""
};
});
g_form.setValue('u_cost_plan_changes', JSON.stringify(data));
}
</script>
<g2:evaluate var="jvar_savedData" jelly="true">
var data = '';
var gr = new GlideRecord('project_change_request');
gr.addQuery('sys_id', RP.getParameterValue('sys_id'));
gr.query();
if (gr.next()) {
data = gr.getValue('u_cost_plan_changes');
}
data;
</g2:evaluate>
<div id='cost_plan_baseline'>
<div class="section-title" style="width:80%"> <b>Baseline Cost Plan</b></div>
<table style="width:80%">
<g2:evaluate>
var baselineConfig = {
dmn_demand: 'dmn_demand_baseline',
pm_project: 'pm_project_baseline'
};
var totals1 = {};
var allResourceTypes1 = {};
var query = '';
var className = current.parent.sys_class_name;
var category = current.category.getDisplayValue();
query ='^ORbaseline_nameLIKE' + current.parent.getDisplayValue() + ' ' + category;
var baselineGR=new GlideRecord(baselineConfig[className]);
baselineGR.addEncodedQuery(' baseline_name=Baseline on Approved State-' + current.parent.getDisplayValue() + query);
baselineGR.addQuery(className, current.parent.sys_id);
baselineGR.orderByDesc('sys_created_on');
baselineGR.setLimit(1);
baselineGR.query();
if (baselineGR.next()) {
var costPlanBaselineGR=new GlideRecord('cost_plan_baseline');
costPlanBaselineGR.addQuery('parent', baselineGR.getValue('sys_id'));
costPlanBaselineGR.query();
while (costPlanBaselineGR.next()) {
var costPlanCategory=costPlanBaselineGR.resource_type.getDisplayValue();
allResourceTypes1[costPlanCategory]=true;
var costBreakdownGR=new GlideRecord('cost_plan_breakdown_baseline');
costBreakdownGR.addQuery('parent', costPlanBaselineGR.getValue('sys_id'));
costBreakdownGR.query();
while (costBreakdownGR.next()) {
var fiscalPeriod=costBreakdownGR.getDisplayValue('fiscal_period') || '' ;
var fiscalYear=fiscalPeriod.split(':')[0].trim();
var cost=parseFloat(costBreakdownGR.getValue('cost_default_currency')) || 0;
if (!totals1[fiscalYear]) {
totals1[fiscalYear]={ Total: 0 };
}
if (!totals1[fiscalYear][costPlanCategory]) {
totals1[fiscalYear][costPlanCategory]=0;
}
totals1[fiscalYear][costPlanCategory] +=cost;
totals1[fiscalYear].Total +=cost;
}
}
}
for (var fyKey1 in totals1) {
totals1[fyKey1].Total=parseFloat(totals1[fyKey1].Total.toFixed(2));
for (var rt1 in allResourceTypes1) {
if (totals1[fyKey1][rt1]===undefined) {
totals1[fyKey1][rt1]=0;
}
totals1[fyKey1][rt1]=parseFloat(totals1[fyKey1][rt1].toFixed(2));
}
}
var orderedTotals1 = {};
var orderedRT1 = Object.keys(allResourceTypes1).sort();
var sortedFY1 = Object.keys(totals1).sort(function(a, b) {
return parseInt(a.replace('FY','')) - parseInt(b.replace('FY',''));
});
for (var m in sortedFY1) {
var fyName1 = sortedFY1[m];
orderedTotals1[fyName1] = { Total: totals1[fyName1].Total };
for (var idx1 in orderedRT1) {
var resTypeName1=orderedRT1[idx1];
orderedTotals1[fyName1][resTypeName1]=totals1[fyName1][resTypeName1];
}
}
</g2:evaluate>
<j2:forEach items="$[Object.keys(orderedTotals1)]" var="jvar_fy_key2" varStatus="jvar_index1">
<g2:evaluate jelly="true">
var fyData2 = orderedTotals1[jelly.jvar_fy_key2];
</g2:evaluate>
<j2:if test="$[jvar_index1 == 0]">
<tr>
<th>Year</th>
<j2:forEach items="$[Object.keys(fyData2)]" var="jvar_key3">
<th>$[jvar_key3]</th>
</j2:forEach>
</tr>
</j2:if>
<tr>
<td>$[jvar_fy_key2]</td>
<j2:forEach items="$[Object.keys(fyData2)]" var="jvar_key4">
<g2:evaluate jelly="true">
var fyData3 = fyData2[jelly.jvar_key4];
</g2:evaluate>
<td>$[fyData3]</td>
</j2:forEach>
</tr>
</j2:forEach>
</table>
<div class="section-title" style="width:80%"> <b>Draft Cost Plan</b></div>
<table style="width:80%">
<g2:evaluate jelly="true">
var allResourceTypes = {};
var costPlanMap = {};
var costPlanGR = new GlideRecord('cost_plan');
costPlanGR.addQuery('top_task', current.getValue('parent'));
costPlanGR.query();
while (costPlanGR.next()) {
var costPlanId = costPlanGR.getUniqueValue();
var costPlanType = (costPlanGR.getDisplayValue('resource_type') || '').trim();
costPlanMap[costPlanId] = costPlanType;
}
var totals = {};
var costBreakdownGR = new GlideRecord('cost_plan_breakdown');
costBreakdownGR.addQuery('task', current.getValue('parent'));
costBreakdownGR.addNotNullQuery('cost_plan');
costBreakdownGR.query();
while (costBreakdownGR.next()) {
var parentCostPlan = costBreakdownGR.getValue('cost_plan');
if (!costPlanMap[parentCostPlan]) continue;
var mappedResourceType = costPlanMap[parentCostPlan];
allResourceTypes[mappedResourceType] = true;
var fp = costBreakdownGR.getDisplayValue('fiscal_period') || '';
var fy = fp.split(':')[0].trim();
var cost = parseFloat(costBreakdownGR.getValue('cost_default_currency')) || 0;
if (!totals[fy]) {
totals[fy] = { Total: 0 };
}
if (!totals[fy][mappedResourceType]) {
totals[fy][mappedResourceType] = 0;
}
totals[fy][mappedResourceType] += cost;
totals[fy].Total += cost;
}
for (var fyKey in totals) {
totals[fyKey].Total = parseFloat(totals[fyKey].Total.toFixed(2));
for (var rt in allResourceTypes) {
if (totals[fyKey][rt] === undefined) {
totals[fyKey][rt] = 0;
}
totals[fyKey][rt] = parseFloat(totals[fyKey][rt].toFixed(2));
}
}
var orderedTotals = {};
var orderedRT = Object.keys(allResourceTypes).sort();
var sortedFY = Object.keys(totals).sort(function(a, b) {
return parseInt(a.replace('FY','')) - parseInt(b.replace('FY',''));
});
for (var n in sortedFY) {
var fyName = sortedFY[n];
orderedTotals[fyName] = { Total: totals[fyName].Total };
for (var idx in orderedRT) {
var resTypeName=orderedRT[idx];
orderedTotals[fyName][resTypeName]=totals[fyName][resTypeName];
}
}
</g2:evaluate>
<j2:forEach items="$[Object.keys(orderedTotals)]" var="jvar_fy_key" varStatus="jvar_index">
<g2:evaluate jelly="true">
var fyData = orderedTotals[jelly.jvar_fy_key];
</g2:evaluate>
<j2:if test="$[jvar_index == 0]">
<tr>
<th>Year</th>
<j2:forEach items="$[Object.keys(fyData)]" var="jvar_key1">
<th>$[jvar_key1]</th>
</j2:forEach>
</tr>
</j2:if>
<tr>
<td>$[jvar_fy_key]</td>
<j2:forEach items="$[Object.keys(fyData)]" var="jvar_key">
<g2:evaluate jelly="true">
var fyData1 = fyData[jelly.jvar_key];
</g2:evaluate>
<td>$[fyData1]</td>
</j2:forEach>
</tr>
</j2:forEach>
</table>
<div class="section-title" style="width:80%"> <b>Cost plan change classification</b></div>
<table style="width:80%">
<tr>
<th>Year</th>
<th>Baselined Cost plan</th>
<th>Draft cost plan</th>
<th>Carry over/Forward</th>
<th>Supplemental</th>
<th>Release</th>
<th>New cost plan</th>
<th>Change to be Claaified</th>
</tr>
<j2:forEach items="$[Object.keys(orderedTotals)]" var="jvar_fy_key1">
<g2:evaluate jelly="true">
var year = jelly.jvar_fy_key1;
var fyData1 = orderedTotals[year];
var fyData4 = orderedTotals1[year];
var data = jelly.jvar_savedData;
var data1 = JSON.parse(data);
var carry = '';
var supp = '';
var rel = '';
if (data1[year]) {
carry = data1[year].carry_over || '';
supp = data1[year].supplemental || '';
rel = data1[year].release || '';
}
</g2:evaluate>
<tr>
<td>$[jvar_fy_key1]</td>
<td>$[fyData4.Total]</td>
<td>$[fyData1.Total]</td>
<td>
<input type="number" id="carry_over_$[jvar_fy_key1]" name="carry_over_$[jvar_fy_key1]" value="$[carry]" />
</td>
<td>
<input type="number" id="supplemental_$[jvar_fy_key1]" name="supplemental_$[jvar_fy_key1]" value="$[supp]" />
</td>
<td>
<input type="number" id="release_$[jvar_fy_key1]" name="release_$[jvar_fy_key1]" value="$[rel]" />
</td>
<td>Germany</td>
<td>Germany</td>
</tr>
</j2:forEach>
</table>
</div>
</j:jelly>I have designed the HTML Structure as below :
<div id='cost_plan_baseline'>
<div class="section-title" style="width:80%">
<b>Baseline Cost Plan</b>
</div>
<table style="width:80%">
<!-- table content -->
</table>
<div class="section-title" style="width:80%">
<b>Draft Cost Plan</b>
</div>
<table style="width:80%">
<!-- table content -->
</table>
<div class="section-title" style="width:80%">
<b>Cost plan change classification</b>
</div>
<table style="width:80%">
<!-- table content -->
</table>
</div> <!-- THIS CLOSES THE cost_plan_baseline DIV -->However , when it is being rendered by the browser the <div id='cost_plan_baseline> tag is being closed after the first <div> as shown in the screenshot below:
What is the possible solution for this?
@Naveen20 Can you please help?
1 REPLY 1
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
14 hours ago
Try this possible fix
1. Move all `<g2:evaluate>` computation blocks out of the tables, above the outer div:
<g2:evaluate>
// all baseline + draft calculations here
</g2:evaluate>
<div id="cost_plan_baseline">
<table>
<tbody>
<j2:forEach ...>
<tr>...</tr>
</j2:forEach>
</tbody>
</table>
</div>
2. Wrap rows in an explicit `<tbody>` — gives the parser a valid container.
3. Replace per-row `<g2:evaluate jelly="true">` with inline `$[...]` expressions, or precompute a flat row array above the div.
Show/hide
Client script on the reference field:
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading) return;
var el = document.getElementById('cost_plan_baseline');
if (el) el.style.display = newValue ? 'block' : 'none';
}
