I have a lot of dialog in vaadin flow which I want let user print them. I know how to print the whole page as below code but I want only the dialog above the page be printed.
Button btnPrint = new Button( "Print…" );
btnPrint .addClickListener( ( ClickEvent < Button > clickEvent ) ->
{
// this Prints the current page
UI.getCurrent().getPage().executeJs( "print();" );
} );
I did also tried this with java script but no success.
window.printPartOfPage = function (divPrintId) {
console.log("Inside printPartOfPage");
var printContent = document.getElementById(divPrintId);
var WinPrint = window.open('', '', 'letf=100,top=100,width=600,height=600');
WinPrint.document.write(printContent.innerHTML);
WinPrint.document.close();
WinPrint.focus();
WinPrint.print();
WinPrint.close();
}
Any Idea how to do it?
Both vaadin-dialog and vaadin-dialog-overlay are custom elements and use Shadow DOM. One of the main features of a Shadow DOM is to mask the initial DOM (called "Light DOM") with a new DOM (called "Shadow DOM"). Therefore, without some sort of web reflection, a call to innerHTML is not returning what you expected. Also, if it did work, you would have used outerHTML.
One solution is to use CSS...
Define a new style:
.no-print {
display: none !important;
}
And when you want to print, add that class to all elements except vaadin-dialog and vaadin-dialog-overlay:
UI.getCurrent().getPage().executeJs("" +
"const body = document.body;" +
"" +
"for(let child = body.firstChild; child !== null; child = child.nextSibling) {" +
" if(child.tagName !== 'vaadin-dialog' && child.id !== 'overlay') {" +
" child.classList.add('no-print');" +
" }" +
" " +
"}" +
"" +
"window.print();" +
"" +
"for(let child = body.firstChild; child !== null; child = child.nextSibling) {" +
" child.classList.remove('no-print');" +
"}"
);
Obviously, this is not the most efficient method. Particularly because other elements, such as scripts, will get the no-print class. But hopefully this gives you an idea.
I hope this helped!