Search code examples
javascriptsvgselectorbarcodesiblings

Javascript selector first sibling after button


My page contains over 300 unique barcodes within a table, similar to the table below. I gave each barcode its own download button, but how do I make the button download only the first sibling barcode directly after itself?

<tr>
  <td>
    (product name)
  </td>
  <td>
    (other data)
  </td>
  <td>
    (even more data)
  </td>
  <td>
    <button type="button" class="downloadBarcode"></button> <!-- Download button -->
    <svg class="barcode" etc...></svg> <!-- SVG generated by JsBarcode -->
  </td>
</tr>
<tr>
  (another product with data and a barcode)
</tr>

This is the script I am currently using, but it obviously only works for the first barcode element in the long list:

  document.querySelector(".downloadBarcode").onclick = () => {
    svgToPng(document.querySelector('.barcode').outerHTML, (imgData) => {
      const download = document.createElement('a');
      download.href = imgData;
      download.download = 'barcode.png';
      download.click();
    });
  }

  const svgToPng = (svg, callback) => {
    const url = URL.createObjectURL(new Blob([svg], {
      type: 'image/svg+xml'
    }));
    svgUrlToPng(url, (imgData) => {
      callback(imgData);
      URL.revokeObjectURL(url);
    });
  }

  const svgUrlToPng = (svgUrl, callback) => {
    const svgImage = document.createElement('img');
    svgImage.style.position = 'absolute';
    svgImage.style.top = '-9999px';
    document.body.appendChild(svgImage);
    svgImage.onload = function() {
      const canvas = document.createElement('canvas');
      canvas.width = svgImage.clientWidth;
      canvas.height = svgImage.clientHeight;
      const canvasCtx = canvas.getContext('2d');
      canvasCtx.drawImage(svgImage, 0, 0);
      const imgData = canvas.toDataURL('image/png');
      callback(imgData);
      document.body.removeChild(svgImage);
    };
    svgImage.src = svgUrl;
  }

Solution

  • Use event.currentTarget to get the element that was clicked on. Then you can use nextElementSibling to get the element after it.

    document.querySelector(".downloadBarcode").onclick = (event) => {
      svgToPng(event.currentTarget.nextElementSibling.outerHTML, (imgData) => {
        const download = document.createElement('a');
        download.href = imgData;
        download.download = 'barcode.png';
        download.click();
      });
    }