Skip to content

Multi-Product Printing

Demonstrates batch printing with multiple products in a single job.

Live Demo

Source Code

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>TopBridge SDK — Multi-Product Printing Example</title>
  <style>
    body { font-family: system-ui, sans-serif; max-width: 900px; margin: 40px auto; padding: 0 20px; }
    h1 { color: #333; }
    .section { margin: 20px 0; padding: 16px; border: 1px solid #ddd; border-radius: 8px; }
    button { padding: 8px 16px; margin: 4px; cursor: pointer; border: 1px solid #ccc; border-radius: 4px; background: #fff; }
    button:hover { background: #f0f0f0; }
    button:disabled { opacity: 0.5; cursor: not-allowed; }
    #log { background: #1a1a1a; color: #0f0; padding: 16px; border-radius: 8px; font-family: monospace;
           font-size: 13px; max-height: 400px; overflow-y: auto; white-space: pre-wrap; }
    table { border-collapse: collapse; width: 100%; }
    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    th { background: #f5f5f5; }
    input { padding: 6px 10px; border: 1px solid #ccc; border-radius: 4px; width: 80px; }
    .product-row { display: flex; gap: 8px; align-items: center; margin: 4px 0; }
    .product-row input { width: auto; }
  </style>
</head>
<body>
  <h1>Multi-Product Printing Example</h1>
  <p>Demonstrates printing multiple products in a single job, each with different copy counts.</p>

  <div class="section">
    <h2>1. Preflight</h2>
    <button id="btn-preflight" onclick="runPreflight()">Run Preflight</button>
    <span id="preflight-status"></span>
  </div>

  <div class="section">
    <h2>2. Product List</h2>
    <div id="product-list">
      <div class="product-row">
        <input class="p-name" value="Apple" placeholder="Name" style="width:120px">
        <input class="p-price" value="3.99" type="number" step="0.01" placeholder="Price">
        <input class="p-currency" value="$" style="width:40px" placeholder="Currency">
        <input class="p-unit" value="/kg" style="width:60px" placeholder="Unit">
        <input class="p-copies" value="2" type="number" min="1" max="9999" style="width:60px" placeholder="Copies">
      </div>
      <div class="product-row">
        <input class="p-name" value="Banana" placeholder="Name" style="width:120px">
        <input class="p-price" value="1.99" type="number" step="0.01" placeholder="Price">
        <input class="p-currency" value="$" style="width:40px" placeholder="Currency">
        <input class="p-unit" value="/lb" style="width:60px" placeholder="Unit">
        <input class="p-copies" value="1" type="number" min="1" max="9999" style="width:60px" placeholder="Copies">
      </div>
      <div class="product-row">
        <input class="p-name" value="Orange" placeholder="Name" style="width:120px">
        <input class="p-price" value="4.50" type="number" step="0.01" placeholder="Price">
        <input class="p-currency" value="$" style="width:40px" placeholder="Currency">
        <input class="p-unit" value="/kg" style="width:60px" placeholder="Unit">
        <input class="p-copies" value="3" type="number" min="1" max="9999" style="width:60px" placeholder="Copies">
      </div>
    </div>
    <div style="margin-top:8px">
      <select id="template-select"><option value="">-- run preflight first --</option></select>
      <select id="printer-select"><option value="">-- run preflight first --</option></select>
    </div>
    <button id="btn-print" onclick="runPrint()" disabled>Batch Print</button>
  </div>

  <div class="section">
    <h2>Log</h2>
    <div id="log"></div>
  </div>

  <script type="module">
    const { TopBridgeClient } = await import('https://esm.sh/@appzgatenz/label-print-topbridge-js')

    const client = new TopBridgeClient({ debug: true })
    let preflightResult

    function log(msg) {
      const el = document.getElementById('log')
      const time = new Date().toLocaleTimeString()
      el.textContent += `[${time}] ${msg}\n`
      el.scrollTop = el.scrollHeight
    }

    window.runPreflight = async () => {
      const btn = document.getElementById('btn-preflight')
      btn.disabled = true
      btn.textContent = 'Checking...'
      log('--- Running preflight ---')

      try {
        preflightResult = await client.preflight.run({
          onStepChange: (step) => log(`  Step: ${step}...`)
        })

        log('✓ Preflight passed')
        document.getElementById('preflight-status').textContent = '✓ Ready'

        const printerSelect = document.getElementById('printer-select')
        printerSelect.innerHTML = ''
        for (const p of preflightResult.printers.data.printers ?? []) {
          const opt = document.createElement('option')
          opt.value = p.name
          opt.textContent = p.name + (p.isDefault ? ' (default)' : '')
          if (p.isDefault) opt.selected = true
          printerSelect.appendChild(opt)
        }

        const templates = await client.templates.list()
        const templateSelect = document.getElementById('template-select')
        templateSelect.innerHTML = ''
        for (const t of templates.data.templates ?? []) {
          const opt = document.createElement('option')
          opt.value = t.code || t.id
          opt.textContent = t.name
          templateSelect.appendChild(opt)
        }

        document.getElementById('btn-print').disabled = false
      } catch (err) {
        log(`✗ Preflight failed: ${err.message}`)
        document.getElementById('preflight-status').textContent = '✗ Failed'
      } finally {
        btn.disabled = false
        btn.textContent = 'Run Preflight'
      }
    }

    window.runPrint = async () => {
      const btn = document.getElementById('btn-print')
      btn.disabled = true
      btn.textContent = 'Printing...'

      const rows = document.querySelectorAll('.product-row')
      const products = []
      rows.forEach(row => {
        const name = row.querySelector('.p-name').value
        const price = parseFloat(row.querySelector('.p-price').value)
        const currency = row.querySelector('.p-currency').value
        const unit = row.querySelector('.p-unit').value
        const copies = parseInt(row.querySelector('.p-copies').value) || 1
        if (name) products.push({ name, price, currency, unit, copies })
      })

      const template = document.getElementById('template-select').value
      const printer = document.getElementById('printer-select').value

      log(`--- Batch printing ${products.length} products ---`)

      try {
        const result = await client.print.execute({
          template,
          printer,
          products,
          fieldTypes: { price: 'price' },
        })

        log(`✓ Print successful`)
        log(`  Total copies: ${result.data.printedCopies}`)
        log(`  Template: ${result.data.templateName}`)
        log(`  Job ID: ${result.data.jobId}`)

        if (result.warnings?.length) {
          log('  Warnings:')
          for (const w of result.warnings) {
            log(`    [${w.code}:${w.reason}] ${w.message}`)
          }
        }
      } catch (err) {
        log(`✗ Print failed: ${err.message}`)
      } finally {
        btn.disabled = false
        btn.textContent = 'Batch Print'
      }
    }

    // --- iframe height auto-resize ---
    function reportHeight() {
      const height = document.documentElement.scrollHeight
      window.parent.postMessage({ type: 'resize-iframe', height }, '*')
    }
    window.addEventListener('load', reportHeight)
    window.addEventListener('resize', reportHeight)
    const observer = new MutationObserver(reportHeight)
    observer.observe(document.body, { childList: true, subtree: true })
  </script>
</body>
</html>