Code readingHow-to

Build a barcode value from checkboxes without stale separators

Compose a barcode value from checkbox-selected fields with one expression that joins only the checked fields and drops a separator when a box turns off.

LumaSpec Vision10 min قراءة مشاركة على LinkedIn

في هذه الصفحة 12 أقسام
  1. 01What you need
  2. 02Settle the payload contract first
  3. 03Compose the value: dash inside the condition
  4. 04Test all eight checkbox states
  5. 05Why append-on-check never converges
  6. 06Fix the field order; retire click order
  7. 07Pick a separator outside every field's alphabet
  8. 08What the payload costs at print time
  9. 09Ship it to a PLC, a printer and a scan point
  10. 10When the usual answer is wrong
  11. 11Deploy checklist
  12. 12Questions

A screen that lets an operator tick ProductID, SampleID and SubSampleID has to turn those ticks into one barcode string that always matches the boxes. The tempting build is an event script that appends a field on check — and it fails on the first uncheck, because nothing removes the field or its dash. The fix is to stop accumulating and start computing: one expression rebuilds the whole value from the current checkbox states whenever any of them changes. This guide gives you the expression pattern, the separator and field-order decisions to settle first, a test table for all eight on/off combinations, and the label-width arithmetic that shows what each toggled field costs at print time.

What you need

Three checkbox Booleans: prodOn, sampOn and subOn, each starting at false. Three source strings, typed as strings: prodId, sampId and subId, with illustrative values P-4821, S-0093 and Q-7; your real values come from view parameters, recipe tags or the MES. Add one separator character chosen once, and a destination for the result: a display, PLC string memory or the print file.

You also need a binding that lists every checkbox as an input and recomputes whenever any input changes. Do not write to the value from checkbox event handlers — that accumulation pattern is exactly what this guide replaces.

Settle the payload contract first

Four decisions remove every edge case before you write the expression. Field order: fixed and canonical — ProductID, then SampleID, then SubSampleID — never click order. Separator: one character that appears in no field value; audit real data before picking. All boxes off: the value is an empty string, and every consumer treats empty as no selection. Checked but empty: a field whose value is empty is excluded, exactly like an unchecked box. Write the four rules down; the far end parses against them. If another station splits this string back into fields, it needs the same rules — the parse side is its own task, covered in Split barcode string data into fields: parse lot and part numbers.

Compose the value: dash inside the condition

Each enabled, non-empty field contributes its value plus one dash; skipped fields contribute nothing. The only cleanup is dropping one trailing dash, which leaves an empty string untouched and cannot create a leading or a doubled dash.

value = dropLastDash( if(prodOn and prodId != "", prodId + "-", "") + if(sampOn and sampId != "", sampId + "-", "") + if(subOn and subId != "", subId + "-", "") )

Build it in six steps:

  1. Order the fields canonically: ProductID, SampleID, SubSampleID.
  2. Write one conditional per field that emits the value plus a dash only when the box is on and the value is not empty.
  3. Concatenate the three conditionals in that fixed order.
  4. Strip the trailing dash when the result ends in one; leave the empty string alone.
  5. Bind the whole expression to every checkbox, so any single change recomputes it.
  6. Guard every consumer against the empty result before the screen goes live.

Many SCADA platforms implement the binding as an expression structure: it references every checkbox and re-evaluates on any change. One term there reads if({value}['chkProd'], {view.params.ProductID}, ""); move the dash into the true branch so the separator travels with the value: if({value}['chkProd'], {view.params.ProductID} + "-", "").

The alternative — joining the three terms with dashes and cleaning up afterwards — needs two repairs instead of one:

Assembly pattern Raw string (ProductID on, SampleID off, SubSampleID on) Cleanup needed
Join the three terms with "-" P-4821--Q-7 Collapse the doubled dash, trim the edges
Dash inside each if() P-4821-Q-7- Drop one trailing character

Test all eight checkbox states

Three Booleans give 2^3 = 8 combinations, and the value depends on states rather than events, so one pass proves every possible click sequence. Sweep them at commissioning:

prodOn sampOn subOn Raw string Final value Characters
off off off (empty) (empty) 0
on off off P-4821- P-4821 6
off on off S-0093- S-0093 6
off off on Q-7- Q-7 3
on on off P-4821-S-0093- P-4821-S-0093 13
on off on P-4821-Q-7- P-4821-Q-7 10
off on on S-0093-Q-7- S-0093-Q-7 13
on on on P-4821-S-0093-Q-7- P-4821-S-0093-Q-7 17

Every row follows from two moves: an off box or an empty value contributes nothing, and one trailing dash disappears. To sweep quickly, drive the three Booleans temporarily from a 0-7 integer and step through it — eight writes, eight strings, no clicking.

Why append-on-check never converges

Walk the event script through a normal edit. Check ProductID: the script appends and the value reads P-4821. Check SampleID: P-4821-S-0093. Uncheck ProductID: no handler fires, so the string still shows a product code the operator just removed. Patching the event model means an uncheck handler per field, position-aware deletion and a master reset button for the residue — and the result still depends on click order.

The expression has none of those paths: the uncheck flips a Boolean, the binding recomputes, and the same scan cycle shows S-0093. The root fault is trusting a stored copy instead of the current inputs — the same trap documented for property-node reads that return a stale value on repeated read; the cure has the same shape: recompute from live inputs.

Fix the field order; retire click order

Click order breaks the data even when the script works. One operator ticks SampleID then ProductID and produces S-0093-P-4821; a colleague ticks the same boxes the other way round and produces P-4821-S-0093. Same selection, two payloads, and a positional parser assigns the first field to ProductID in one case and to SampleID in the other. Match verification and traceability fail with no error anywhere. Sort the enabled fields by a fixed index before joining, and the payload becomes a function of the selection alone.

Pick a separator outside every field's alphabet

A dash reads naturally, but IDs like P-4821 already contain one, so P-4821-S-0093 splits ambiguously: three fields or four? Export a sample of every field's real values and choose a character none of them uses; | or ~ survives most ID schemes. Validate entries so the separator can never be typed. If the payload feeds a GS1 workflow, skip the free choice entirely — application identifiers with the standard FNC1 separator define the fields for you, as GS1 QR code FNC1 separators: encode and verify data walks through.

What the payload costs at print time

Every character you add gets printed. Code 128 encodes each data character as an 11-module symbol; start, check and stop symbols add 35 modules, and the quiet zone takes 10 modules per side at the ISO/IEC 15417 minimum. That gives an estimate:

width ≈ (55 + 11 × N) × X

with N the payload character count and X the module width. Worked example, all three fields on: the payload P-4821-S-0093-Q-7 has N = 17 characters, so modules = 55 + 11 × 17 = 242, and at X = 0.25 mm (10 mil) the label needs 242 × 0.25 mm = 60.5 mm. Turn SubSampleID off and N drops to 10: modules = 55 + 11 × 10 = 165, width = 41.3 mm. Each toggled character therefore costs 11 × 0.25 mm = 2.75 mm of width.

The estimate assumes Code Set B throughout, which letters-and-dash payloads satisfy; long digit runs can pack two characters per symbol and shrink it. Module width, reading angle and read distance trade against each other — Code 128 barcode module size, reading angle and reader distance works that side of the choice.

Ship it to a PLC, a printer and a scan point

To a PLC: write the characters into string memory with a length and a new-data handshake, so a half-written string is never taken as complete — Storing ASCII barcode strings in PLC memory: bytes, words and clears and Copy barcode data to a string only on a new read handshake show the receive side. To a printer: the same string drives the label file, and the width estimate above says whether it still fits the web. All boxes off leaves the value empty, so guard the display and treat empty as no-read — Hide a barcode display when no read: guard empty values is the display-side pattern.

At the line, the printed label is scanned again and compared with the composed value. The pass/fail set-up is in Barcode match verification: build a pass/fail check station, and the lookup-table variant in Verify scanned barcodes against a PLC lookup table.

For a compact station reader, the MV-ID3013PM-12M-WBN pairs a 12 mm lens with a 1.3 MP global-shutter sensor over Fast Ethernet.

Fixed code readersHikrobot MV-ID3013PM-12M-WBN 12mm focal length 1.3 MP Compact Industrial Code ReaderMV-ID3013PM-12M-WBN
Interface
Fast Ethernet
Resolution
Up to 3 MP
Shutter
Global
Lens mount
M12
$1,979.00View part

Throughput headroom scales with decode rate: the LS-CRD-0028 processes 2560 x 2048 frames at 30 fps and up to 60 codes/s. Bench proofing goes the other way — a wired handheld such as the LS-HCR-0001, 1.0 MP on USB 2.0, checks a printed sample at the desk. Shortlist from the fixed code readers and handheld code readers categories or the camera finder, or contact us to size the read point.

Fixed code readers2560 x 2048 fixed code reader, 30 fps, 60 codes/s, 8 mm lens (LS-CRD-0028)LS-CRD-0028
Interface
Fast Ethernet
Resolution
5 MP
$920.00View part
Handheld code readersHandheld industrial barcode reader, 1.0 MP, USB 2.0 (LS-HCR-0001)LS-HCR-0001
Resolution
Up to 3 MP
Shutter
Global
$539.00View part

When the usual answer is wrong

If operators genuinely need selection order in the payload, keep the fixed-order expression and encode the order as its own field, or accept that every consumer must parse by identifiers rather than position. If field values can contain any printable character, no separator is safe — switch to fixed-width padding or GS1 identifiers. If two screens and a PLC all compose the same string, you have three sources of truth; compute once, in one binding or one computed tag, and distribute the result. And if the payload must shrink for the web, drop a field from the contract rather than abbreviating values, because abbreviations break match verification silently. Related payload and decode decisions are collected under the code-reading topic.

Deploy checklist

Run down this list before the screen goes live; each line closes a failure shown above.

  • Contract: field order, separator and empty-value rules written down and agreed with whoever parses the string.
  • Expression: every condition tests box on and value not empty, and exactly one trailing-strip operation cleans up.
  • Sweep: all 2^n states reproduce the table; n = 3 means eight rows, including the empty-value case.
  • Empty guard: the display hides or placeholders, and the PLC treats empty as no-read.
  • Handshake: the PLC copies only on a new-read flag, and the printer file regenerates on every change.
  • Width: the longest allowed payload fits the web with quiet zones — 60.5 mm for the 17-character example at 10 mil.
  • Scan point: the reader is mounted below eye level and the expected-versus-scanned comparison is running.

أسئلة

What should the barcode value be when all checkboxes are unchecked?

An empty string, by contract. Guard both consumers: the display hides the field or shows a placeholder, and the PLC or printer treats empty as no selection rather than as a value. If your process needs a visible marker, add one fixed placeholder string such as NONE and define it in the payload contract — never leave the empty case undefined, because that is when blanks get logged as real reads.

Can the payload follow the order the operator clicked the boxes?

It can, but it should not. Click order makes the string depend on the operator, so the same selection produces different payloads and a positional parser assigns fields to the wrong names. Keep the fixed canonical order in the expression. If a consumer stores the whole string without ever parsing it, order is harmless — but fix the order anyway so archived values stay comparable.

Which separator character is safest between barcode fields?

Whichever character appears in none of the field values. Export real samples and check: dashes live inside many part IDs, so | or ~ usually survives. Enforce the choice with input validation so the separator can never be typed into a field. For a GS1 workflow, use application identifiers with the standard FNC1 separator and the choice disappears entirely.

How many test cases does the expression need?

One per checkbox state combination: n checkboxes means 2^n rows, so three boxes need eight. Include the row where a box is checked but its value is empty — it must behave exactly like an unchecked box. Drive the Booleans from a counter during the sweep rather than clicking, and compare the binding output against the contract table row by row.

Does adding a field change the printed label size?

Yes, roughly linearly. Code 128 adds an 11-module symbol per character, so at a 0.25 mm module width every character costs about 2.75 mm of label width, plus about 14 mm of fixed start, check, stop and quiet-zone overhead. Turning on the 7-character SampleID field in the worked example widens the label by roughly 19 mm.