Convert HTML document to PDF with Angular - javascript

I have an Angular 11 application and I want to download a PDF from a given HTML. this HTML is not a component from my Angular app, is a HTML document independent from the application, like this:
<!DOCTYPE html>
<html lang='en' xmlns='ttp://www.w3.org/1999/xhtml'>
<head>
<style> p { color: red; } </style>
</head>
<body>
<p>hi there</p>
</body>
</html>
I want to be able to load this HTML and save as a PDF as it is. I tried using pdfmake to create the PDF but it ignores the style on the head tag.
import pdfMake from 'pdfmake/build/pdfmake'
import pdfFonts from 'pdfmake/build/vfs_fonts';
pdfMake.vfs = pdfFonts.pdfMake.vfs;
import htmlToPdfmake from 'html-to-pdfmake';
export class MyComponent {
myHtml: string = "<!DOCTYPE html><html lang='en'
xmlns='ttp://www.w3.org/1999/xhtml'><head><style> p { color: red; }
</style></head><body><p>hi there</p></body></html>";
constructor() {
let html = htmlToPdfmake(this.myHtml);
let documentDefinition = { content: html };
pdfMake.createPdf(documentDefinition).open();
}
}
PDF generated:
the text should be red, why is it not red?

You can add inline styles like that
<!DOCTYPE html>
<html lang='en' xmlns='ttp://www.w3.org/1999/xhtml'>
<head>
</head>
<body>
<p style="color: red;">hi there</p>
</body>
</html>

Related

Setting color theme in Google Sheets sidebar via cell value

I would like the Google Sheets sidebar to open with a color set in cell Sheet1:A1. My current code works (I suspect there may be a more efficient way to do this), but the CSS steps through each theme in root until it lands on the correct theme.
For example, if A1 is set to 'Orange', calling the sidebar will load with the body first as 'Default' and then switch to 'Orange'. Is there a way to load the correct root theme on the initial page load instead of stepping through the themes in root?
Google Apps Script
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu("Sidebar")
.addItem("Show sidebar", "showSidebar")
.addToUi();
}
function showSidebar() {
var htmlWidget = HtmlService.createTemplateFromFile('Test').evaluate()
.setTitle("Theme Test");
SpreadsheetApp.getUi().showSidebar(htmlWidget);
}
function getColorTheme() {
colorTheme = SpreadsheetApp.getActive().getRange("Sheet1!A1").getDisplayValue();
return colorTheme;
}
HTML for Sidebar
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
:root,
:root.Default {
--bg-color: #45818e;
}
:root.Orange {
--bg-color: #e69138;
}
body {
background-color: var(--bg-color);
}
</style>
<script>
function setTheme(colorTheme) {
document.documentElement.className = colorTheme;
}
</script>
</head>
<body>
<p>Hello world</p>
<script>
google.script.run.withSuccessHandler(setTheme).getColorTheme();
</script>
</body>
</html>
From your situation, how about the following patterns?
Pattern 1:
In this pattern, HTML is modified using Google Apps Script and the modified HTML is used with HtmlService.createHtmlOutput().
Google Apps Script side:
function showSidebar() {
var colorTheme = SpreadsheetApp.getActive().getRange("Sheet1!A1").getDisplayValue();
var html = HtmlService.createHtmlOutputFromFile('Test').getContent().replace("{{colorTheme}}", colorTheme);
var htmlWidget = HtmlService.createHtmlOutput(html).setTitle("Theme Test");
SpreadsheetApp.getUi().showSidebar(htmlWidget);
}
HTML side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
:root,
:root.Default {
--bg-color: #45818e;
}
:root.Orange {
--bg-color: #e69138;
}
body {
background-color: var(--bg-color);
}
</style>
<script>
document.documentElement.className = "{{colorTheme}}";
</script>
</head>
<body>
<p>Hello world</p>
</body>
</html>
Pattern 2:
In this pattern, HTML is modified using HTMl template and the modified HTML is used with HtmlService.createHtmlOutput().
Google Apps Script side:
function ashowSidebar() {
var colorTheme = SpreadsheetApp.getActive().getRange("Sheet1!A1").getDisplayValue();
var htmlWidget = HtmlService.createTemplateFromFile('Test')
htmlWidget.colorTheme = colorTheme;
SpreadsheetApp.getUi().showSidebar(htmlWidget.evaluate().setTitle("Theme Test"));
}
HTML side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
:root,
:root.Default {
--bg-color: #45818e;
}
:root.Orange {
--bg-color: #e69138;
}
body {
background-color: var(--bg-color);
}
</style>
<script>
document.documentElement.className = "<?= colorTheme ?>";
</script>
</head>
<body>
<p>Hello world</p>
</body>
</html>
Note:
From the recent benchmark of the HTML template, it seems that in the current stage, the process cost of evaluate() is a bit high. Ref So, I proposed the above 2 patterns with and without an HTML template.
In this case, <html class="{{colorTheme}}"> and <html class="<?= colorTheme ?>"> might be able to be used instead of Javascript. But, I'm not sure about your actual situation. So, in this answer, Javascript is used as a sample modification.
References:
createHtmlOutput(html)
HTML Service: Templated HTML
createTemplateFromFile(filename)

JS Return HTML Title as H1 Headline

first of all: I‘m not a coder!
I want to inject a dynamic h1 based on page title on a webpage.
Example: <title>Garden</title>
Now I need this as H1 class - I want to include this H1 after a given div class <div class="teaser"></div>
It is may totally simple and I already read some stuff but i don‘t get it…
Fairly trivial
window.addEventListener('DOMContentLoaded', function() {
const h1 = document.createElement('h1')
h1.innerHTML = document.title;
document.querySelector(".teaser").insertAdjacentElement("afterend", h1)
})
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Garden</title>
</head>
<body>
<div class="teaser">Teaser</div>
</body>
</html>

I was not able to see images while converting html page to pdf using javascript

here is my code while i download pdf images attributes of html are missing.
suppose in cases like generating invoices we should print tables containing details along with logo.
but images are not displaying in downloaded pdf using this code.Provide me with possible resolution and reason for this.thanks in advance
$(document).on('click', '#btn', function() {
let pdf = new jsPDF();
let section = $('body');
let page = function() {
pdf.save('pagename.pdf');
};
pdf.addHTML(section, page);
})
html,
body {
overflow-x: hidden;
}
#btn {
padding: 10px;
border: 0px;
margin: 50px;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<title>HTML with Image</title>
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
<style type="text/css">
</style>
</head>
<body>
<button id="btn">Convert to PDF</button>
<div id="text">
<h2>HTML Page with Image to PDF</h2>
<img src="http://photojournal.jpl.nasa.gov/jpeg/PIA17555.jpg" width="300px">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.0.272/jspdf.debug.js"></script>
<script src="custom.js"></script>
<script type="text/javascript">
</script>
</body>
</html>
all the html elements are working fine except images . kindly help me with resolving this.
jsPdf does not support adding images the way you are trying to add them, because addtHtml function uses the html2canvas module, to convert your Html to canvas, so jsPdf can render it into pdf. Please check this link below.
https://weihui-guo.medium.com/save-html-page-and-online-images-as-a-pdf-attachment-with-one-click-from-client-side-21d65656e764

Generating pdf from external html file and css

I have an external html file that I would like to print as a PDF but I'm having trouble getting the example code to work as intended and I'm obviously missing something trivial when implementing it.
This is my code so far:
function savePDF(data) {
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html');
let pdf = new jsPDF('p','pt','a4');
pdf.addHTML(
htmlDoc.body, // HTML DOM element.
);
pdf.save("test.pdf");
}
Where data is a string containing the html of the external webpage I wish to convert to a pdf.
Chrome is generating a TypeError: Cannot read property 'innerWidth' of null
This for example works perfectly (using fromHTML instead of addHTML) but the css/styling is missing:
function savePDF(data) {
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html');
let pdf = new jsPDF('p','pt','a4');
pdf.fromHTML(htmlDoc.body.innerHTML, 0, 0, {},
function(){pdf.save('test.pdf');
});
}
Sample html that I'm using:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PDF Test</title>
</head>
<body>
<div id="capture" style="padding: 10px; background: #f5da55">
<h4 style="color: #000; ">Hello world!</h4>
</div>
</body>
</html>
As the documentation says the addHtml method is deprecated ( http://raw.githack.com/MrRio/jsPDF/master/docs/global.html#addHTML), so i played a bit with your example and if you updated your code like this it works. You still have to work a bit to fix the width of div in the pdf.
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js" integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/" crossorigin="anonymous"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
</head>
<body>
<div id="capture" style="padding: 10px; background: #f5da55;">
<h4 style="color: #000; ">Hello world!</h4>
</div>
</body>
<script type="text/javascript">
function savePDF(data) {
let pdf = new jsPDF('p','pt','a4');
pdf.html(data, {
callback: function (doc) {
doc.save("test.pdf");
}
});
}
savePDF(document.body.innerHTML)
</script>
</html>

Should I write an implementation of a custom element whithin <body>?

Like the below code, the implementation of a custom element is imported.
And is naked, which means, the imported document has no body and head.
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="import" href="html/demo-element.html">
</head>
<body>
<demo-element>hello world</demo-element>
</body>
</html>
demo-element.html
<template>
<style type="text/css">
div {
background-color: #F2CEE5;
padding: 10px;
}
</style>
<div>
<content></content>
</div>
</template>
<script type="text/javascript">
(function() {
var thisDoc = document.currentScript.ownerDocument;
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var t = thisDoc.querySelector('template');
var clone = document.importNode(t.content, true);
this.createShadowRoot().appendChild(clone);
}
}
});
var element = document.registerElement('demo-element', {
prototype: proto
});
})();
</script>
I want you see the below which is the result which chrome dev tool shows.
The imported document has head and body and the implementation is in head somehow.
I want to know if this is common or I should write head and body in demo-element.html and put the implementation in the body.

Categories

Resources