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>