foreverAnIntern
foreverAnIntern

Reputation: 501

Printing HMTL elements

I need to print a list of elements on the click of a button. I have the data in my back-end, and am generating a table of elements with 5 elements in each row through the following:

const labelDataHTML = (values) => (
  <table id="dataTable" style={{ width: "100%" }}>
    <caption>Labels</caption>
    {_.chunk(values, 5).map((item, index) => (
      <tr key={`row-${index}`} className={`row`}>
        {index % 5 !== 0
          ? item.map((obj) => <td>{obj}</td>)
          : item.map((obj) => <td>{obj}</td>)}
      </tr>
    ))}
  </table>
);

I am retrieving the HTML object in another function which I am triggering on click of a button (found this code block on other SO pages):

const printData = (domElement) => {
  var printContents = document.querySelector("table").innerHTML;
  var originalContents = document.body.innerHTML;

  document.body.innerHTML = printContents;
  window.print();

  document.body.innerHTML = originalContents;
};

There are 2 problems with this. 1 is that I lose all the HTML table elements upon clicking the print button, and it just becomes a long list without spaces. Second is that once I click it, all other elements on my page become unresponsive. I have attached a [sandbox][1] as well.

I'm new to React and javascript in general. Appreciate all the help!

UPDATE: Here's how I solved the problem: I found this solution based on a ton of other questions I found on SO:

const labelDataHTML = values =>
    ReactDOMServer.renderToString(
        <table id="dataTable" style={{ width: "100%" }}>
            <caption>Labels</caption>
            {_.chunk(values, 5).map((item, index) => {
                return (
                    <tr className={`row`}>
                        {index % 5 !== 0
                            ? item.map(obj => <td>{obj}</td>)
                            : item.map(obj => <td>{obj}</td>)
                        }
                    </tr>
                );
            })}
        </table>
    );

const PrintLabels = labelData => {
    let domElement = labelDataHTML(labelData)
    let windowInstance = window.open("");

    windowInstance.document.write(domElement);

    windowInstance.print();
    windowInstance.close();
};

[1] : https://codesandbox.io/s/kind-cache-81qgu

Upvotes: 1

Views: 128

Answers (2)

Emad Dehnavi
Emad Dehnavi

Reputation: 3441

For your first issue, you need to wrap your printContents within html table tag.

`<table>${printContents}</table>`

For your second problem, you need to create a window instance and open the print dialog in new window and then close the instance. You can refactor your function to something like this:

const printData = (domElement) => {
   let printContents = document.querySelector("table").innerHTML;
   let windowInstance= window.open("");
   windowInstance.document.write(`<table>${printContents}</table>`);
   windowInstance.print();
   windowInstance.close();
};

Upvotes: 2

trixn
trixn

Reputation: 16344

You are temporarily changing the contents of the page in a way which I find to be a very hacky way to achive that.

A better way would be to hide every other element on the page only for print with css:

@media print {
  body * {
    visibility: hidden;
  }
  #dataTable,
  #dataTable * {
    visibility: visible;
  }

  #dataTable {
    position: absolute;
    left: 0;
    top: 0;
  }
}

Then you can simply print the table using:

window.print();

Edit adoring-worker-tpijh

Upvotes: 0

Related Questions