Hi...
Ah brilliant! Thanks for pointing those out. I checked this one out as well from your util link. I have now a couple of solid use cases to work on - https://playground.jsreport.net/w/anon/0~cRmrQ~
Thanks again 🙏
Hi...
Ah brilliant! Thanks for pointing those out. I checked this one out as well from your util link. I have now a couple of solid use cases to work on - https://playground.jsreport.net/w/anon/0~cRmrQ~
Thanks again 🙏
Hi I'm struggling to populate a Table of Content where I want to incorporate subheaders in the template as part of the Table of Content.
For instance and to start with, here's an example of how it currently looks on my current setup:
This is all fine and this is achieved with this code in the helper section:
function tableOfContents (pdfPages) {
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
const sections = pdfPages.map((d) => d.group?.title ?? "Blank").filter((d) => d !== "Blank").filter(onlyUnique)
const contents = [];
for (const section of sections) {
let firstPageOfSection = 0;
let firstPageSeen = false;
for (let i = 0; i < pdfPages.length; i++){
if (pdfPages[i].group?.title === section) {
if(!firstPageSeen) {
firstPageOfSection = i + 1;
firstPageSeen = true;
}
}
}
contents.push({
sectionName: section,
firstPageOfSection: firstPageOfSection
})
}
return contents;
}
And here in the template:
<ul class="toc__list">
{{#each (tableOfContents $pdf.pages)}}
<li class="toc__item">
<span class="toc__title">{{this.sectionName}}</span>
<span class="toc__spacer"></span>
<span class="toc__page">{{this.firstPageOfSection}}</span>
</li>
{{/each}}
</ul>
So... what I want to do is to have something like this in the Table of content:
So, the subheaders, and here is where I'm struggling with, which is getting them from the template by targeting all the <h2> tags with a class name, i.e. <h2 class="toc__listed">
I was trying to do something like this:
function tableOfContents(pdfPages) {
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
const sections = pdfPages.map((d) => d.group?.title ?? "Blank").filter((d) => d !== "Blank").filter(onlyUnique)
const contents = [];
for (const section of sections) {
let firstPageOfSection = 0;
let firstPageSeen = false;
const subsections = [];
for (let i = 0; i < pdfPages.length; i++) {
if (pdfPages[i].group?.title === section) {
if (!firstPageSeen) {
firstPageOfSection = i + 1;
firstPageSeen = true;
}
// Extract h2 headers with class .toc__listed from page content
const h2Regex = /<h2 class="toc__listed".*?>(.*?)<\/h2>/g;
const matches = pdfPages[i].content.match(h2Regex);
if (matches) {
const subSections = matches.map(match => match.replace(/<\/?h2.*?>/g, '').trim());
subsections.push(...subSections);
}
}
}
contents.push({
sectionName: section,
firstPageOfSection: firstPageOfSection,
subsections: subsections
});
}
return contents;
}
And then update the template with something like this to match this updated code:
{{#each (tableOfContents $pdf.pages)}}
<li class="toc__item">
<span class="toc__title">{{this.sectionName}}</span>
<span class="toc__spacer"></span>
<span class="toc__page">{{increment this.firstPageOfSection 1}}</span>
<ul>
{{#each this.subsections}}
<li>{{this}}</li>
{{/each}}
</ul>
</li>
{{/each}}
But I don't seem to go anywhere without running in to a number of errors.
So, my question would be:
Many thanks in advance for any help you guys can provide!
Ok, this worked.
const mxEventsData = {{{toJS MXEvents}}};
const chartData = [];
mxEventsData.forEach((event) => {
event.part.forEach(({ partName, totalEventsCost }) => {
chartData.push({
date: event.date,
totalEventsCost: Number(totalEventsCost.replace(/\D/g, '')), // Format to numeric value
partName,
});
});
});
Thanks a million, once again!
Ahh brilliant! I think I'm getting somewhere with your pointer. Thanks a mill @bjrmatos ! I'll report back, how it goes.
Hi,
This might be a bit silly since I'm a bit bit new with JSReport, but I'm trying to do something like this to iterate over my data source and compile with the {{#each}}
helper in the template where I have an inline <script>
I'm using for a chart. At the moment, this doesn't seem to be working:
const chartData = [
{{#each MXEvents}}
{
date: "{{this.date}}",
{{#each this.part}}
partName: {{this.partName}},
totalEventsCost: {{this.totalEventsCost}}
{{/each}}
},
{{/each}}
]
The above {{each}}
theoretically should work, because if I do the same in the template, like this, it populates it perfectly:
<ul>
{{#each MXEvents }}
<li>{{this.date}}</li>
<ul>
{{#each this.part}}
<li>{{this.partName}} - {{this.totalEventsCost}}</li>
<ul>
{{#each this.event}}
<li>{{ this.eventName }}</li>
{{/each}}
</ul>
{{/each}}
</ul>
{{/each}}
</ul>
I'm not sure if I'm doing it right or if there is a better way to do this. In essence, what I'm trying to achieve is to bring this data into the javascript, so I can loop it through and populate it for a Highcharts.js code.
Any help pointing me in the right direction will be highly appreciated 🙏. Not sure if it'll be of any use, but here is the full code I'm using.
//<!-- chart container. -->
<div id="mx_events_chart" class="mb-4"></div>
<script>
// Extract the data and prepare the series for Highcharts
const chartData = [
{{#each MXEvents}}
{
date: "{{this.date}}",
{{#each this.part}}
partName: {{this.partName}},
totalEventsCost: {{this.totalEventsCost}}
{{/each}}
},
{{/each}}
]
// console.log(chartData);
//const testing = document.getElementById('testing');
//testing.textContent = JSON.stringify(chartData);
// Extract unique dates and partNames
const uniqueDates = [];
const uniquePartNames = [];
chartData.forEach(({ date, partName }) => {
if (!uniqueDates.includes(date)) {
uniqueDates.push(date);
}
if (!uniquePartNames.includes(partName)) {
uniquePartNames.push(partName);
}
});
// Create an object to store series data based on partName
const seriesData = {};
// Initialize seriesData with zero values for each date
uniquePartNames.forEach((partName) => {
seriesData[partName] = {
name: partName,
data: uniqueDates.map((date) => {
const dataPoint = chartData.find((data) => data.date === date && data.partName === partName);
return dataPoint ? dataPoint.totalEventsCost : 0;
}),
};
});
// Convert seriesData object into an array of series
const chartSeries = Object.values(seriesData);
// Create the Highcharts chart
Highcharts.chart('mx_events_chart', {
chart: {
type: 'column',
},
title: {
text: '',
},
yAxis: {
title: {
text: ''
}
},
xAxis: {
categories: uniqueDates,
},
credits: {
enabled: false,
},
plotOptions: {
column: {
stacking: 'normal'
},
series: {
animation: false,
},
},
series: chartSeries,
});
</script>