In this post we will look at different ways for printing multiple labels from a web application.
Option #1
The first option is just to call the print() method several times. Each call to print() will produce a single label. Between calls you will call other library functions like setObjectText() to update the label’s content. The pseudo-code is like this:
var label = dymo.label.framework.openLabelXml("<?xml>..."); // label #1 label.setObjectText("Text", "Some text"); label.print("DYMO LabelWriter 450 Turbo"); // label #2 label.setObjectText("Text", "Some other text"); label.print("DYMO LabelWriter 450 Turbo"); // label #3 // ...
This option is straightforward but unfortunately is not very efficient. Each call to print() function creates a separate print job. This might be a problem if hundreds of labels are being printed. But more important it might be not fast enough. The reason is that due to the printer hardware design some LabelWriter models might need to reverse feed a label at the beginning of each print job. Thus printing each label in a separate print job might be up to 5-10 times slower that printing all labels in one print job.
The solution is to do printing in one print job, so each label is printed as a single job’s “page”. For this there is option #2.
Option #2 – Printing Using a LabelSet
A “labelset” contains data to be printed on labels. Conceptually it is very similar to a dataset/recordset or a database table. A labelset consists of a set of records. Each record represents data for a single label. A record consists of a set of “fields”. Each field name is a name of an object on the label. A field value is text to be printed for that object. A record can be seen as a dictionary/associative array. The dictionary’s keys are label object names. The dictionary’s values are text for the label object. The dictionary can have only one key, e.g. if there is only one object on the label. But also it can have multiple keys to specify data for different label objects. It is NOT necessary to specify data for each object on the label; if a record does not have an appropriate key the object text will remain as-is (so, the object is a kind of ‘static’ text).
To do multiple label printing two pieces of information need to be defined. One piece defines what to print and the other piece defines how to print. “How to print” means how/where to put data on the label. That is specified by the label file. “What to print” is the actual data. That is specified by a labelset.
One more way to look at multiple label printing from the point of view of the MVC (Model-View-Controller) design pattern. In this case a labelset is the Model, the data to be processed/printed. A label (file) is the View. It specifies a presentation or layout for the data to be printed. And the library is the Controller, it binds the label and the labelset in print() operation.
LabelSet API
The Labelset API is quite simple. To create a labelset call dymo.label.framework.LabelSetBuilder constructor, like
var labelSet = new dymo.label.framework.LabelSetBuilder();
To add a new record, call the addRecord() method of the LabelSetBuilder object,
var record = labelSet.addRecord();
To set record data, call the setText() method. The first parameter is an object/field name, the second – an object text/field value,
record.setText("Description", itemDescription); record.setText("ItemCode", itemCode);
To print a labelset, just pass it as a third argument to print() method (the first argument is a parameter name, and the second argument is printing parameters; you can use empty string to specify default printing parameters),
label.print("DYMO LabelWriter 450 Turbo", '', labelSet);
Samples
To demonstrate using LabelSet we will look at two samples. Both of them use Google Docs spreadsheet as a data source. They take a spreadsheet data using Google Data JSON API and convert to appropriate labelset. The spreadsheet itself is displayed on a web page as well, so it is more clear what data are printed. Although for these samples spreadsheets are read-only it is possible to make them “editable”, so “live” data will be printed.
Sample #1 – Addresses
A spreadsheet for this sample contains address data. Each part of the address – name, street, city, state, zip – is in it’s own column. So, each spreadsheet row contains a full address, and specifies data for one label. The sample page is here, the java script code is here.
Upon page load a request is made to get the spreadsheet’s data:
function loadSpreadSheetData() { removeOldJSONScriptNodes(); var script = document.createElement('script'); script.setAttribute('src', 'http://spreadsheets.google. com/feeds/list/tSaHQOgyWYZb6mUPGgrsOGg/1/public/values?alt=json-in-script&callback=window. _loadSpreadSheetDataCallback'); script.setAttribute('id', 'printScript'); script.setAttribute('type', 'text/javascript'); document.documentElement.firstChild.appendChild(script); };
This is done by dynamically creating a <script> element to avoid cross-domain security restrictions. Upon request completion a callback function is called; the callback gets passed the returned spreadsheet’s data in json format to a function that generates a labelset and saves it in labelSet variable.
function loadSpreadSheetDataCallback(json) { labelSet = createLabelSet(json); };
createLabelSet() function iterates through all spreadsheet rows, and for each row it creates one labelset record. Each record contain only one “field”, because the label we going to print contains only one address object named “Address”.
function createLabelSet(json) { var labelSet = new dymo.label.framework.LabelSetBuilder(); for (var i = 0; i < json.feed.entry.length; ++i) { var entry = json.feed.entry[i]; var name = entry.gsx$name.$t; var street = entry.gsx$streetaddress.$t; var city = entry.gsx$city.$t; var state = entry.gsx$state.$t; var zip = entry.gsx$zip.$t; var address = name + 'n' + street + 'n' + city + ', ' + state + ' ' + zip; var record = labelSet.addRecord(); record.setText("Address", address); } return labelSet; }
As you see, the function is pretty straightforward. The most complex part is to get the spreadsheet’s columns values (name, street, city, etc variables) and combine them into one address block (address variable).
A label file is fetched from the server on the page loading as well. The label is saved in the “label” variable. We used jQuery library to fetch the label xml, but any other AJAX toolkit library can be used as well.
function loadLabel() { // use jQuery API to load label $.get("Address.label", function(labelXml) { label = dymo.label.framework.openLabelXml(labelXml); }, "text"); }
The final step is printing itself. It is done from Print button’s onclick handler.
printButton.onclick = function() { try { if (!label) throw "Label is not loaded"; if (!labelSet) throw "Label data is not loaded"; label.print(printersSelect.value, '', labelSet); } catch (e) { alert(e.message || e); } };
For simplicity the sample throws an exception if the label or labelset is still being loaded. If everything is OK, the printing itself is as simple as calling the print() method. There should be three labels printed with the following content:
Sample #2 – Inventory List
The second sample is very similar to the first one. The only difference is the data itself. For this sample the data is an inventory list with two columns. The first column is a textual description of an inventory item. The second is the item’s “code”/”id”. Instead of combining different columns into one field (as in the first sample), these two column are used independently to provide data for two different objects on the label. The “ItemDescription” column provides data for the text object, while the “ItemCode” column provides data for the barcode object. So, each record in the labelset will have two “fields”, one for each object. This is done by calling setText() method twice.
function createLabelSet(json) { var labelSet = new dymo.label.framework.LabelSetBuilder(); for (var i = 0; i < json.feed.entry.length; ++i) { var entry = json.feed.entry[i]; var itemDescription = entry.gsx$itemdescription.$t; var itemCode = entry.gsx$itemcode.$t; var record = labelSet.addRecord(); record.setText("Description", itemDescription); record.setText("ItemCode", itemCode); } return labelSet; }
The full code is available here. Four labels should be printed:
Conclusion
We have looked at two different ways to print multiple labels. The second one that uses a “labelset” concept is a recommended way to print multiple labels. You could even use it to print a single label, in this case you will not have to change your code much if you need to print multiple labels in the future. The data for labels might come from different sources, .e.g. entered directly by user, read from a corporate database, or fetched from a third-party provider like Google Docs as in the blog’s samples.
In the next post we will look at various ways to format text data on a label, e.g. how to specify different font size, font style, etc on character-by-character basis.