Hi, I followed this tutorial but I noticed that it caused some problems, this is because in the code written by @church sometimes we entered an infinite loop, this is because when the input changed, the comparison between the old and the new input was not done correctly, we were comparing a raw html string against a formatted html string coming from the innerHTML method, it follows that the formatting, the tabulations, can be different, with the consequence that the comparison fails, entering an infinite loop and causing quite a few problems.
this is the code I added:
temporaryTemplateContents = document.getElementById("temporaryTemplateContents");
temporaryTemplateContents.innerHTML = model.content;
temporaryTemplateCSS = document.getElementById("temporaryTemplateCSS");
temporaryTemplateCSS.innerHTML = model.css;
and this is the modification on the comparison:
if(startingContent == temporaryTemplateContents.innerHTML && startingCSS == temporaryTemplateCSS.innerHTML) { return; }
this is the code in full:
<html>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- put any fonts you need here -->
<style>
<!-- here is where you'll need to style your html for printing, especially if you're also displaying it natively inside of your retool app -->
</style>
</head>
<body>
<script src="https://cdn.tryretool.com/js/react.production.min.js" crossorigin></script>
<script src="https://cdn.tryretool.com/js/react-dom.production.min.js" crossorigin></script>
<!-- get the HTML to PDF bundle -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js"></script>
<script>
const injectCSS = css => {
let el = document.createElement('style');
el.type = 'text/css';
el.innerText = css;
document.head.appendChild(el);
return el;
};
var retoolModel;
// subscribe to model changes
window.Retool.subscribe(function(model) {
if (!model) { return }
retoolModel = model;
var startingContent = document.getElementById("templateContents").innerHTML;
var startingCSS = document.getElementById("templateCSS").innerHTML;
// new logic for better comparation -- added by Panacci Karim at 16 October 2024 21:44 GMT+2
temporaryTemplateContents = document.getElementById("temporaryTemplateContents");
temporaryTemplateContents.innerHTML = model.content;
temporaryTemplateCSS = document.getElementById("temporaryTemplateCSS");
temporaryTemplateCSS.innerHTML = model.css;
//if the content has not changed, take no action. This prevents the component from entering an endless loop.
if(startingContent == temporaryTemplateContents.innerHTML && startingCSS == temporaryTemplateCSS.innerHTML) { return; }
// move our printed content into an element we can access later
document.getElementById("templateContents").innerHTML = model.content;
document.getElementById("templateCSS").innerHTML = model.css;
injectCSS(model.css);
pdprint();
});
function pdprint() {
// our function to generate and display the pdf in a new window
var opt = {
margin: 0.5,
filename: "raw.pdf", //This doesn't matter since we're not actually downloading the file; we'll name the file when using utils.downloadFile with the base64 binary output of this component
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
};
window.html2pdf().set(opt)
.from(document.getElementById("templateContents").innerHTML)
.outputPdf()
.then(function(pdfas) {
retoolModel.pdf_blob = btoa(pdfas);
window.Retool.modelUpdate(retoolModel);
} );
}
</script>
<!-- ... This stores the HTML content that we used to generate the PDF -->
<div id="templateContents" style="display:none"></div>
<div id="templateCSS" style="display:none"></div>
<div id="temporaryTemplateContents" style="display:none"></div>
<div id="temporaryTemplateCSS" style="display:none"></div>
</body>
</html>