Jun 172010
 

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:

img1 img2 img3
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:

img10 img11 img12 img13

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.

  48 Responses to “DYMO Label Framework JavaScript Library: Print Multiple Labels”

  1. One thing I found interesting and stumped me for a bit before I debugged through the framework code: when using a labelset if you do
    var record = labelSet.addRecord();
    record.setText(“NAME”,”Alex”);
    record.setText(“PRICE”,5); // this causes a crash

    There is an issue, it bugs out at line 1769 of the latest hosted version. Its where you use objValue.indexOf. Obviously the issue here was me being an idiot and setting the price field to a 5 and not “5”, but it is a mistake you might consider catching in the framework and converting to string so that doesn’t fail.

    Alex

    • I should be clearer, it only errors when you actually go to print the thing and it converts the labelset to xml, also is there any place to help and post bug reports other than the developers blog? or is this fine?

  2. PS: framework rocks btw, this is so much nicer than the old way

  3. Is there a way to use LabelSets with an applescript and from a pc command line

    • LabelSet API is not available from AppleScript. On Windows, the LabelSets are supported as a part of DYMO Label Framework API. There is no sample yet, but the code would be like this:

      
      void PrintMultipleLabelsWithLabelSet()
      {
          // load label layout
          ILabel label = Label.Open("MyTextLabel.label");
      
          // create a label set
          LabelSetBuilder labelSetBuilder = new LabelSetBuilder();
      
          // populate label set with data for three labels
          // the code assumes that the label contains an object with reference name set to "TEXT"
          for (int i  = 1; i <= 3; ++i)
              labelSetBuilder.AddRecord().AddText("TEXT", string.Format("label {0}", i));
      
          // get a reference to first connected printer
          ILabelWriterPrinter printer = Framework.GetLabelWriterPrinters().First(p => p.IsConnected) as ILabelWriterPrinter;
      
          // print three labels with default printing parameters
          label.Print(printer, null, labelSetBuilder.Xml);
      }
      
      
       

      see DymoLabelFramework.chm from SDK installer for the LabelSetBuilder class reference

  4. Greetings is it possible to use the dymo labelwriter with silverlight?

    • yes, it is possible, and there are several ways to archive it:

      • using DYMO Label Framework JavaScript library. You will have to write some js code to interact with Silverlight app, e.g. to get data to print from it.
      • using Silverlight 4 printing API. In this case you interact with LabelWriter as with any other printer using printer drivers
      • using DYMO Label Framework by COM-interop available in Silverlight 4. This will work on Windows only. here is a sample
  5. I am using SDK 8.2.3 V1.0. I wish to programmatically set the number of copies.
    I defined the params as:

    var printParamsXml = ‘

    2
    ‘;

    I get the desired number of labels with:

    var labels = document.getElementById(‘labels’)

    I have been unable to “discover” how to set the value of “Copies” at run time.

    Any ideas? suggestions?

    Thanks,
    Bill

    • use createLabelWriterPrintParamsXml() function

      /** Creates an xml stream suatable to pass to printLabel() function as printParamsXml parameter
      // Created printing parameters are for printing on LabelWriter printers
      // Parameters:
      // – params – an JavaScript object with following properties (not all properties have to be defined, if a property is not defined a default value will be used)
      // params.copies – number of copies to print
      // params.jobTitle – print job title/description
      // params.flowDirection – prints label content as left-to-right or right-to-left use FlowDirection enum to specify values
      // params.printQuality – printing quality, one of ‘Text’, ‘BarcodeAndGraphics’, or ‘Auto’
      // params.twinTurboRoll – the roll to print on if the printer is TwinTurbo. One of ‘Left”, ‘Right’, or ‘Auto’
      */
      dymo.label.framework.createLabelWriterPrintParamsXml = function(params)

      Then pass params xml to printLabel function, like

      dymo.label.framework.printLabel(printerName, printParamsXml, labelXml)

  6. Does this do it?
    var labels = document.getElementById(‘labels’);
    printParamsXml = createLabelWriterPrintParamsXml(params.copies = labels.value);
    label.print(printerName,printParamsXml);

    • no

      var labels = document.getElementById(‘labels’);
      printParamsXml = dymo.label.framework.createLabelWriterPrintParamsXml({copies: labels.value});
      label.print(printerName,printParamsXml);

  7. Thank you for helping an old functional programmer :-)

  8. I am curious if you have any documentation or samples that illustrate how to format the data on the label (e.g. bold, italics, etc…). You eluded to such features above but I have been unable to location any information on how to accomplish this.

    My specific situation is that I am using the JavaScript library to print from a web application and utilize the LabelSet feature to print multiple copies if reqeusted. Therefore, I am using the labelset.addrecord.setText method to get the text on the label. I have seen in the JS docs that there is also a setTextMarkup method but I am unclear on how to utilize this method.

    Please advise and I apologize if the information has been here and I just haven’t found it.

    • Hi Eric,

      Yes, setTextMarkup() has to be used. Unfortunately there are no samples and the documentation is very limited.

      Anyway, the markup string passed to the function should contain a xml string according to the schema. The allowed tags are simple html tags for text formatting, e.g. ‘<b>’ to make text bold, ‘<i>’ for italic, etc. To specify font name and size use ‘font’ tag with ‘family’ and ‘size’ attributes. E.g. using the following markup text:

      "<font family=’Courier New’ size=’36’>6×7=<b>42</b></font>"

      the output will look like

  9. Thank you Vladimir…that was a helpful start.

    I am having trouble using the “” element in the setTextMarkup function call. When I pass “Address Line 1” to the function, everything prints as expected. However when I simply add “” to the text (e.g. “Address Line 1” I get the following error message “‘documentElement’ is null or not an object.”

    I am currently working with a label layout with an Address Object named “ADDRESS” and I would like to pass all 3 or 4 lines of an address to it to be displayed on the label. I am assuming that I would need to utilize the tag in order to tell the Address Object where to begin a new line. Is this correct?

    Thanks again for your help.

    • could you provide the full sample (seems like WordPress ‘ate’ some formatting)? I assume you are trying to insert line lines? to do that use

      ‘<br/> tag. Make sure it is ‘<br/> not just ‘<br>, so the markup string is well formed xml

  10. Sorry about that…yes, WordPress did “eat” some of my last post. I think I was able to discern your advice and have tried it as well (as you will see).

    If I pass “Line 1” to setTextMarkup everything is fine. However, if I add a break tag “()” to the end I receive the error message ‘documentElement is null or not an object.” If it doesn’t come through, the characters between the double quotes should be “lessthan, br, forwardslash, greaterthan”

    If this is the right code, I should be able to send “line1,break,line2,break,line3” to the function and receive a label with three lines on it, correct?

    Thanks again.
    Eric

    • I did not quite understand your note about “()”. Here is a sample that should print two lines:

          var labelSet = new dymo.label.framework.LabelSetBuilder();
          var record = labelSet.addRecord();
          record.setTextMarkup("LeftText", "<font family='Arial' size='14'><i>Measurement 1:<br/></i></font><b><font size='10'>
          passed</font></b>");
      

      The output is like this:

      Measurement 1:
      passed

    • also, you can use ‘new line’ character ‘n’:

          var labelSet = new dymo.label.framework.LabelSetBuilder();
          var record = labelSet.addRecord();
          record.setTextMarkup("LeftText", "<font family='Arial' size='14'><i>Measurement 1:n</i></font><b><font size='10'>
          passed</font></b>");
      
  11. Hi…

    How can I preview a labelset?

    • there is no direct support for that, but it is possible. Basically you will have to call label.setObjectText() for each object data in a record, and then call label.render() to get a preview of the label for the particular record. Do this for each record in a label set.

      Some samples for calling render are available on http://labelwriter.com/software/dls/sdk/samples/js/VisitorManagement/VisitorManagement.html

      • Thanks for your comment… I got one solution for it. This code is inside the “updatePreview” function.

        var valores=labelSet.getRecords(); //get all the records we add to build the labelSet.

        for (cont=1; cont<=valores.length;cont++)
        {
        setAddress(valores[cont-1]["Address"]); //Get the Address of each record and set the Address of the current label with this information..
        pngData = label.render(); //label is defined just like in the preview example.

        labelImage = document.getElementById('DymolabelImage'+cont); //we have several html div's for this .
        labelImage.src = "data:image/png;base64," + pngData;
        }

        :D

  12. I am using Firefox 9.0.1 and the latest dymo framework. The call

    labelSet = new dymo.label.framework.LabelSetBuilder();

    takes a LONG time… around 45-90 seconds. I have tried to only take this hit the first time, and if the labelset is already created, just emptying it and adding records for subsequent calls. This is marginally faster. Anyone else having this problem? Is there some way I can speed it up?

    Thanks
    Kevin

  13. how can you add font styling when you’re using a template? for example my template has 12 text box fields ie txtAddress. I’m dynamically populating the string values but I can’t determine how to set the font size and type?
    var labelXml = template generated from DYMO

    var label = dymo.label.framework.openLabelXml(labelXml);
    label.setObjectText(“txtAddress”,obj[i].Address);

    • Usually you specify font, alignment, etc by creating a label using DLS, so you don’t have to do it in code. It is still possible, but you have to use so called Low-Level API, see the documentation section “Low-Level COM Interface”. We have C++ sample in “DYMO Label v.8 SDKDLS SDKSamplesLow Level COMVisual C++” folder.

  14. I have tried this multiple times, copied your code as is locally, and continue to get “Label is not loaded” on the local machine.

    When I try your page (http://labelwriter.com/software/dls/sdk/samples/js/GoogleSpreadSheet/GoogleSpreadSheet.html) it works just fine.

    What am I missing? What is your code for the GoogleSpreadSheet.html

  15. Hi – is it possible to print multiple DIFFERENT labels, e.g. a scenario where if a group of people attend an event (say 5), I want 1 print job to contain the 5 labels, and then do 1 more label for the leader with some specific info on it. How can I do this in 1 job?

    If it’s impossible to do 1 print job, then if I’m sharing 1 dymo device between several (2 or 3) devices where the registrations are happening, then how can 1 device (which has 1 or more print jobs to send) reserve the printer or block off the others until its jobs are done?

    • You have to add all information from both labels to your .label layout. Then just populate the appropriate data for printing.

      The DYMO SDK doesn’t provide any functionality to block off print jobs. This is handled by the OS. Therefore you have to come up with your own solution.

      • blocking off print-jobs is not such an issue if I can ‘chain’ my labels into 1 xml stream, adn therefore 1 print job per computer. Am I able to do something like this (where I’d then get 3 lable printed out each with formats/designs not necessarily like the other – but always same label size of course)??

        http://shamiso.net/sample.txt

  16. I would like to print multiple labels at once, we’re pulling the data from database into a php array, I want to be able to print a barcode and text, how the js will be in this case, I used the 1st sample above but thery’re using json and spreadsheet and I can’t figurate it out, I tried to remove json but it just doesn’t print. Here’s my js code:

    (function()
    {

    var label;
    var labelSet;
    // called when the document completly loaded
    function onload()
    {
    var itemCode = document.getElementById(‘itemCode’);
    var textTextArea = document.getElementById(‘textTextArea’);
    var printButton = document.getElementById(‘printButton’);

    // prints the label
    printButton.onclick = function()
    {
    try
    {
    // open label
    var labelXml = ‘

    Portrait
    Small30334
    30334 2-1/4 in x 1-1/4 in

    Text

    Rotation0
    False
    True
    Left
    Middle
    AlwaysFit
    True
    False

    Small30334

    ‘;
    var label = dymo.label.framework.openLabelXml(labelXml);

    // set label text
    var labelSet = new dymo.label.framework.LabelSetBuilder();

    for (var i = 0; i < record; ++i)
    {

    var record = labelSet.addRecord();
    record.setText("Description", textTextArea);
    record.setText("ItemCode", itemCode);
    }
    return labelSet;

    // select printer to print on
    // for simplicity sake just use the first LabelWriter printer
    var printers = dymo.label.framework.getPrinters();
    if (printers.length == 0)
    throw "No DYMO printers are installed. Install DYMO printers.";

    var printerName = "";
    for (var i = 0; i < printers.length; ++i)
    {
    var printer = printers[i];
    if (printer.printerType == "LabelWriterPrinter")
    {
    printerName = printer.name;
    break;
    }
    }

    if (printerName == "")
    throw "No LabelWriter printers found. Install LabelWriter printer";

    // finally print the label
    label.print(printerName);

    var records = labelSet.getRecords();
    for (var i = 0; i < records.length; ++i)
    {
    label.setObjectText("Description", records[i]["Description"]);
    label.setObjectText("ItemCode", records[i]["ItemCode"]);
    var pngData = label.render();

    var labelImage = document.getElementById('img' + (i + 1));
    labelImage.src = "data:image/png;base64," + pngData;
    }

    }
    catch(e)
    {
    alert(e.message || e);
    }
    }
    };

    // register onload event
    if (window.addEventListener)
    window.addEventListener("load", onload, false);
    else if (window.attachEvent)
    window.attachEvent("onload", onload);
    else
    window.onload = onload;

    } ());

  17. We have web application running on Windows Azure. We are trying to print client side using the Javascript library and sample.
    However, on the server when we fetch the label we need to populate it with dynamic data. That population process opens the label using the framework.dll and Label.Open(). However, the server does NOT have DYMO 8 installed and we’d like not to have to install it since it is in a cloud environment and technically that machine could be trashed and rebuilt without much notice. Without it installed we get a COM exception.
    Basically, we are just using the library to open the label, check for objects by name and populate the text of the existing object, then spit out the xml again.

    One option we have is to just use .NET framework and XPath to set values, but it would be nicer to use your built in library.
    Any way to accomplish this without having to install DYMO 8 or register COM components?

  18. Do you have any samples on how to connect this to mysql database using php? I have been trying to do this with json but am not having much luck.

  19. is it possible to pull two simple elements from a page to populate label.setObjectText… or do you need to set record?
    cant get it to work correctly…

    I have xml with two objects – text and barcode

    var label = dymo.label.framework.openLabelXml(labelXml);
    var pageid = document.getElementById(‘ID’);
    var pagebarcode = document.getElementById(‘BARCODE’);

    label.setObjectText(“ID”, pageid);
    label.setObjectText(“BARCODE”, pagebarcode);

    label.print(“DYMO LabelWriter 310”);

    i can get this to work by manually entering data into label.setObjectText, but the ID and BARCODE are dynamically generated so want to pull them off a page.
    All i get currently are errors (c.split is not a function) (c is undefined)

    • Did you have much luck with the “c.split is not a function” error?
      I’m getting it as well. It looks like the problem was introduced in 1.2.2. The .js file is so hard to debug as it has been minified.

      • Does this happen with Firefox? Is it working with Chrome?

      • I have had this issue occur as well and I discovered in my case it was happening because I was trying to set label xml values in my label printing script for xml elements that did not exist in the xml. For example, if I had a label defined as barcodeLabel and I called barcodelabel.setObjectText(‘Top Barcode’, barcodeObjectText); but there was no ‘Top Barcode’ element in my label file xml it would throw the c is undefined error. It helps to log the vlaues you are setting to the xml label object to catch the actual cause of the undefined error.

  20. Hi,

    This may not be the right place to post this but I am entirely lost. I want to be able to fill out a spreadsheet and print out directly from googlesheets/excel. Is this possible?

    I am not sure where I am supposed to copy this code from, or how to access DYMO’s SDK as the download option from their website seems to be non-functional.

    I am not a computer-wiz, just a simple genomics researcher, so if anyone could help me with a tech-light walkthough that would be AMAZING. Thank you!

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)