Search code examples
javascriptreactjsdomhtml5-canvashtml2canvas

Facing an issue with removing UI buttons in elements of my downloaded PDF file


I am using JSpdf and html2canvas to download my HTML UI code as a PDF file. However, I want to remove the buttons from the PDF file while keeping it visible in the UI. Currently, I am using the following code to remove the button from the element by making a clone. Still, it is not working and I am getting an error in the console.

**Uncaught (in promise) Unable to find an element in cloned iframe**.

I need to find a solution to remove the buttons from the PDF without removing them from the UI. You can reference the codesandbox link in the UI below.

My task is to remove the UI buttons in my PDF file when I download it.

  pdfDownloadHandler(name, div, removeElement) {
    const input = document.getElementById(div);
    const clone = input.cloneNode(true);
    const removeChildElement = clone.querySelectorAll(removeElement);
    new DocumentFragment().append(...removeChildElement);
    const divHeight = clone.clientHeight;
    const divWidth = clone.clientWidth;
    const ratio = divHeight / divWidth;

    html2canvas(clone).then((canvas) => {
      // Create a new PDF canvas.
      const imgData = canvas.toDataURL('image/jpeg');
      const pdf = new JsPDF('p', 'pt', [canvas.width, canvas.height]);
      // then we get the dimensions from the 'pdf' file itself
      const width = pdf.internal.pageSize.getWidth();
      let height = pdf.internal.pageSize.getHeight();
      height = ratio * width;
      // convert your PDF and save to file
      pdf.addImage(imgData, 'JPEG', 0, 40, width, height);
      pdf.save(`${name}.pdf`); // Download the rendered PDF.
    });
  },
<Grid
container
px={3}
pt={2}
rowSpacing={4}
component="div"
id="downloadDoc"
>
      <Grid item xs={12}>
        <Box display="flex" alignItems="center">
          <Box flexGrow={1}>
            <Typography variant="h3"> Dashboard</Typography>
          </Box>
          <Box display="flex" gap={2}>
            <Button
              id="removeElement"
              variant="contained"
              color="primary"
              title="Download"
              onClick={() => {
                // exportToWord("exportTofile");
              }}
            >
              Other DOWNLOAD
            </Button>
          </Box>
          <Box display="flex" gap={2}>
            <Button
              id="removeElement"
              variant="contained"
              color="primary"
              title="Download Word"
              onClick={() => {
                pdfDownloadHandler(
                  "downloadPdf",
                  "exportTofile",
                  "#removeElement"
                );
              }}
            >
              DOWNLOAD PDF
            </Button>
          </Box>
        </Box>
      </Grid>
  <Typography variant="h4"> summery</Typography>
  <Box
    mt={2}
    display="flex"
    justifyContent="space-between"
    alignItems="center"
  >
    <Box>
      <Typography variant="subtitle2">
        {formikForm.values.summery}
      </Typography>
    </Box>
    <IconButton
      size="small"
      onClick={() => {
        seteditText('summery');
      }}
      title="Edit "
      color="primary"
    >
      <EditIcon />
    </IconButton>
  </Box>
</Grid>
<Grid item xs={12}>
  <Typography variant="h4">purpose and use</Typography>
  <Box
    mt={2}
    display="flex"
    justifyContent="space-between"
    alignItems="center"
  >
    <Box>
      <Typography variant="subtitle2">
        {formikForm.values.purpose}
      </Typography>
    </Box>
    <IconButton
      size="small"
      onClick={() => {
        seteditText('purpose');
      }}
      title="Edit "
      color="primary"
    >
      <EditIcon />
    </IconButton>
  </Box>
</Grid>
<Grid item xs={12}>
  <Typography variant="h4">performance data test</Typography>
  <Box
    mt={2}
    display="flex"
    justifyContent="space-between"
    alignItems="center"
  >
    <Box>
      <Typography variant="subtitle2">
        {formikForm.values.modelData}
      </Typography>
    </Box>
    <IconButton
      size="small"
      onClick={() => {
        seteditText('modelData');
      }}
      title="Edit"
      color="primary"
    >
      <EditIcon />
    </IconButton>
  </Box>
</Grid>

</Grid>

Solution

  • You could reduce all that significantly....

    If we look in the documentation:
    https://github.com/niklasvh/html2canvas/blob/master/docs/configuration.md

    If you wish to exclude certain Elements from getting rendered, you can add a data-html2canvas-ignore attribute to those elements and html2canvas will exclude them from the rendering.

    that is all you need your JS code will no need to do any removals, it could be:

      const pdfDownloadHandler = (name, div) => {
        const clone = document.getElementById(div);
        const ratio = clone.clientHeight / clone.clientWidth;
    
        html2canvas(clone).then((canvas) => {
          // Create a new PDF canvas.
          const imgData = canvas.toDataURL("image/jpeg");
          const pdf = new JsPDF("p", "pt", [canvas.width, canvas.height]);
          // then we get the dimensions from the 'pdf' file itself
          const width = pdf.internal.pageSize.getWidth();
          let height = pdf.internal.pageSize.getHeight();
          height = ratio * width;
          // convert your PDF and save to file
          pdf.addImage(imgData, "JPEG", 0, 40, width, height);
          pdf.save(`${name}.pdf`); // Download the rendered PDF.
        });
      };
    

    and to the boxes containing the buttons you add the data-html2canvas-ignore, like this:

              <Box display="flex" gap={2} data-html2canvas-ignore="true">
                <Button
                  id="otherDownload"
                  variant="contained"
                  color="primary"
                  title="Download Word"
                  onClick={() => {
                    // exportToWord("exportTofile", "exportToDoc");
                  }}
                >
                  Other DOWNLOAD
                </Button>
              </Box>
              <Box display="flex" gap={2} data-html2canvas-ignore="true">
                <Button
                  id="pdfDownload"
                  variant="contained"
                  color="primary"
                  title="Download Word"
                  onClick={() => {
                    pdfDownloadHandler("downloadPdf", "exportTofile");
                  }}
                >
                  DOWNLOAD PDF
                </Button>
              </Box>
    

    working sandbox:
    https://codesandbox.io/s/wispy-sky-dmhf65?file=/demo.tsx