Puppeteer Header and Footer not displayed on first page - google-chrome

I am using Puppeteer v1.6.0 and headers and footers are not displayed on the first page when creating a PDF with the displayHeaderFooter:true option, any idea how to enable this?

According to the Puppeteer Documentation:
page.pdf(options)
options <Object> Options object which might have the following properties:
displayHeaderFooter <boolean> Display header and footer. Defaults to false.
headerTemplate <string> HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them:
date formatted print date
title document title
url document location
pageNumber current page number
totalPages total pages in the document
footerTemplate <string> HTML template for the print footer. Should use the same format as the headerTemplate.
margin <Object> Paper margins, defaults to none.
top <string> Top margin, accepts values labeled with units.
right <string> Right margin, accepts values labeled with units.
bottom <string> Bottom margin, accepts values labeled with units.
left <string> Left margin, accepts values labeled with units.
returns: <Promise<Buffer>> Promise which resolves with PDF buffer.
NOTE Generating a pdf is currently only supported in Chrome headless.
NOTE headerTemplate and footerTemplate markup have the following limitations:
Script tags inside templates are not evaluated.
Page styles are not visible inside templates.
Therefore, make sure that you are using the displayHeaderFooter, headerTemplate, and footerTemplate options appropriately to allow for proper PDF generation.
Also, make sure that you set the font size of the header and footer via CSS (you may need to use inline CSS), and set the margin option of the web page to ensure that the content of the web page does not cover up the header and footer.
Example:
await page.pdf({
path: 'example.pdf',
displayHeaderFooter: true,
headerTemplate: '<div id="header-template" style="font-size:10px !important; color:#808080; padding-left:10px"><span class="date"></span><span class="title"></span><span class="url"></span><span class="pageNumber"></span><span class="totalPages"></span></div>',
footerTemplate: '<div id="footer-template" style="font-size:10px !important; color:#808080; padding-left:10px"><span class="date"></span><span class="title"></span><span class="url"></span><span class="pageNumber"></span><span class="totalPages"></span></div>',
margin: {
top: '100px',
bottom: '200px',
right: '30px',
left: '30px',
},
});

thanks a lot! the problem was that i didn't only have to set the margin in puppeteer but also in the actual page!still does not make a lot of sense to me why it headers/footers were displayed on all of the pages but on the first, but anyway, this was the solution...

I used jsreport for render pdf in nodejs. I have a problem with headerTemplate and footerTemplate don't render when I generate my pdf. There is a lot of code sample to use
'margin': {
top : '100px',
bottom : '200px',
right : '30px',
left : '30px'
}
but it doesn't work for me. I keep searching for two days until i go to see the unitesting for chrome-pdf. here the link https://github.com/jsreport/jsreport-chrome-pdf/blob/master/test/chromeTest.js.
It saw the code as below and it works for me. I need to use marginTop and marginBottom instead of margin object.
const resp = await jsreport.render({
template: {
content: '{#asset src/storages/htmls/pdf/master-card.html}',
engine: 'handlebars',
recipe: 'chrome-pdf',
pdfPassword: {
active: true,
password: '1234'
},
chrome: {
displayHeaderFooter: true,
headerTemplate:'',
footerTemplate:`<h1>Page <span class="pageNumber"></span> of <span class="totalPages"></span></h1>`,
format : 'A4',
marginTop: '80px',
marginBottom:'80px'
},
//javascript helper functions used by templating engines
helpers: helper
},

I solved the problem by adding the margins. The Header and Footer was under the page.
margin: {
top: '100px',
bottom: '200px',
right: '30px',
left: '30px',
},

Well... I need to look for the original margins values. Took some time and found chrome's default mating:
margin: {
top: '0.39in',
left: '0.39in',
bottom: '0.38in',
right: '0.38in',
},

Related

Tailwind css - cover remaining height if there is any else overflow like normal

I am working on a website and on some pages there are very few contents like login page and footer don't reach to bottom, That's why I want main section to cover remaining space if there is any and work like normal if overflow. Basically I want it to work like min-height. I tried using min-height with 100vh and 100% but no desired result.
You can use a custom min height.
<div class="min-h-60">
content...
</div>
In our tailwind config file, you should extend minHeight:
module.exports = {
purge: [],
theme: {
extend: {
minHeight: {
'60': '15rem'
}
}
},
variants: {},
plugins: []
}

How to have transition applied to v-dialog when using "dynamic width", meaning that width="unset"?

Basically, I'm creating a form component that is contained inside a v-dialog. The form component will have different child components that are rendered based on select input. So I have to set width of v-dialog to "unset", so that the width of the dialog will stretch to match its content.
The transition works when I toggle the value of width, eg: either 450px or 300px. The problem is that I don't know beforehand the width of the form contains in the dialog, so I definitely need to use dynamic width.
So far, I can not find anyways to achieve transition when using dynamic width. I was trying to get the width of the form component using refs, but setting width to unset, prevent the transition. By the way, the transition I'm talking about is the transition of the width, when using fixed width, it shows nice transition but not for dynamic width
<div id="app">
<v-app id="inspire">
<div class="text-center">
<v-dialog v-model="dialog" width="unset">
<template v-slot:activator="{ on }">
<v-btn color="red lighten-2" dark v-on="on">
Click Me
</v-btn>
</template>
<v-card>
<v-select v-model="selectedForm" :items="items">
</v-select>
<div v-if="selectedForm==='form-a'" class='form-a'>FormA</div>
<div v-if="selectedForm==='form-b'" class='form-b'>FormB</div>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text #click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</v-app>
</div>
new Vue({
el: "#app",
vuetify: new Vuetify(),
data() {
return {
selectedForm: "form-a",
items: ["form-a", "form-b"],
dialog: false
};
}
});
codepen for using fixed width: https://codepen.io/duongthienlee/pen/MWaBLXm
codepen for using dynamic width: https://codepen.io/duongthienlee/pen/GRpBzmL
Noted that in the example i made in codepen, I defined width already, but the real case is that I don't know beforehand the width of form-a and form-b component. form-a and form-b width will be inherited by its parent div which is v-dialog, so that's why I set the width of v-dialog to be unset.
An example of what I mean "dynamic width": form-a has a select input. When user chooses an item, there will be a request to server to get input labels. So form-a will render multiple input fields based on the response body from server. The response body will contain label and default values information. So that makes the width of form-a becomes dynamic.
I think something like this can work for you.
Change v-dialog like so:
<v-dialog v-model="dialog" :width="forms.find(x => x.name===selectedForm).width">
Modify data() to return a forms prop:
data() {
return {
selectedForm: "form-a",
items: ["form-a", "form-b"],
dialog: false,
forms: [
{
name: 'form-a',
width: 200
},
{
name: 'form-b',
width: 1000
}
]
};
}
What you want to do is get the size of the rendered form, and then apply it to the dialog.
This is a common theme when attempting to animate content with dynamic dimensions.
One way to do this is by:
Set the form's visibility as hidden
Wait for it to render
Get the form's width and set it to the dialog
Unset the form's visibility
The tricky/hacky part is that you have to properly await DOM (setTimeout) and Vue ($nextTick) recalculations. I didn't have to await for Vue's $nextTick in this example, but you probably will if you're rendering nested form components:
<div class="form-container">
<div :style="formStyle('form-a')" class='form-a' ref="form-a">FormA</div>
<div :style="formStyle('form-b')" class='form-b' ref="form-b">FormB</div>
</div>
computed:{
formStyle(){
return form => ({
visibility: this.selectedForm == form ? 'inherit' : 'hidden',
position: this.selectedForm == form ? 'inherit' : 'absolute'
})
}
},
methods: {
async onSelectChange(form){
// async request
await new Promise(resolve => setTimeout(resolve, 1000))
this.selectedForm = form
this.recalculate()
},
async recalculate(){
// wait for DOM to recalculate
await new Promise(resolve => setTimeout(resolve))
const formEl = this.$refs[this.selectedForm]
this.dialogWidth = formEl.clientWidth
this.dialogHeight = formEl.clientHeight
},
...
}
Here's the working code to give you an idea:
https://codepen.io/cuzox/pen/yLYwoQo
If I understand you correctly, then this can be done using css. You can try replace all the fix width in the form with
width: fit-content;
For example in you codepen:
.form-a {
width: fit-content;
height: 350px;
background: blue;
}
.form-b {
width: fit-content;
height: 500px;
background: red;
}
The v-dialog renders into a div with class v-dialog:
It seems the animation only works when the the width is of known value, so it cannot be just "unset". The solution would be to get the width of the child element, and set the width of the v-dialog accordingly with a variable.
See VueJS get Width of Div on how to get the width of the child element.
Let me know if it works, I find this is very interesting.

Ionic 4 custom styling of popover, modal components or pages

My app in Ionic 4 but I can’t understand how to customize components.
And i want to display alignment position top right corner.
I have tried in global.css file as well as component.css file , but didn't any luck.
async getNotifications() {
const popover = await this.popoverController.create({
component: NotificationComponent,
// event: ev,
cssClass: 'notificationCSS',
translucent: true
});
return await popover.present();
}
In notificationCSS :
.notificationCSS{
top: 0px !important;
right: 0px !important;
}
Ref. Url
I had a similar problem in ionic for dynamically (maybe not exactly correct in angnular world) rendered html elements. My component css file didn't pick up the classes that I was targetting. However global.css did. I would try put your css in global again.

Page doesn't start at the top due to height of div

I am currently working with Vuejs and routing to other pages. For my link to photos, I would like a main cover photo that covers the entire screen.
<template>
<div id="album-container">
<div class="cover-image"></div>
<section class='intro'>Lorem </section>
<div class="image-flex-wrap">
<div class="image-cell" v-for="image in images">
<img :src="image">
</div>
</div>
</div>
</template>
.cover-image {
background: url('my photo') #fff no-repeat center center;
background-size: cover;
height: 100vh;
}
This displays the page the way I want it, but the problem arises when I am routed to this page from a page where I have previously scrolled down. Instead of starting at the top of the page, it begins around the middle of my cover-image div. I believe the problem has something to do with the height: 100vh because if I replace it with position: absolute and a width of 100%, then the page will start at the top. However, I would like to refrain from using absolute positioning but don't know enough css to understand why this is occurring.
Thanks for the suggestions.
The issue turned out to be unrelated to Vuejs. I had failed to mention I was using Material Design Lite since I didn't expect it to be the cause but unfortunately it was. Due to the way it works, you no longer scroll on the window object by rather the .mdl-layout__content class supplied by MDL. This was why all scroll properties relating to window was returning 0.
I simply set up a watch method on my routes to force scrollTop.
watch: {
$route() {
document.getElementsByClassName('mdl-layout').scrollTop = 0;
}
}
It can probably be related to scrollBehaviour of your vue-router config as well, try to add following scrollBehaviour in the config:
export default new Router({
mode: 'history',
scrollBehavior: (to, from, savedPosition) => {
if (to.hash) {
return {selector: to.hash}
} else {
return {x: 0, y: 0}
}
},
routes: [
{ path: '/', component: landingView },
....
....
{ path: '/healthcheck', name: 'healthcheck', component: healthCheckView }
]
})

WinJS List GridLayout header above list

How to put header in listview with GridLayout.
When I put header above listview my header take some height and last row in listview is not showed, because of header.
I also found a way to set header in listview directly:
data-win-options="{ header: select('.header') }">
With this my header is positioned on the left side of list, not above the list, like normal header should be.
I did not see any example with listview GridLayout and header section above (for instance I wanna put search box and heading in header).
Any example of this ?
Two solutions are here:
1) This is answer I get from Microsoft:
In the list view the WinJS.UI.GridLayout's viewport is loaded
horizontally.
You need to change the viewport's orientation to vertical. You can do
this by attaching the event onloadingstatechanged event.
args.setPromise(WinJS.UI.processAll().then(function () {
listview.winControl.onloadingstatechanged = function myfunction() {
if (listview.winControl.loadingState == "viewPortLoaded")
{
var viewport = listview.winControl.element.getElementsByClassName('win-viewport')[0];
viewport.className = 'win-viewport win-vertical';
}
}
}));
and change the class win-horizontal to win-vertical.
2) Problem could be also solved adding standard html header and list below header, without data-win-options="{ header: select('.header') }" attribute.
In that case we need to calculate height of the list:
.list {
height: calc(100% - headerHeight);
}