Generate Printable QR Codes From Assets

ServiceNow continues proving to us what a great tool it is for managing your IT assets. And now ServiceNow are really making excellent strides in the mobile phone UI and the tablet UI. So I wanted to put the two together.

What I came up with was a simple way of generating QR codes for assets which could be printed and stuck onto the assets. When scanned by a desktop engineer out on site, ServiceNow will automatically load into the relevant window, speeding up the need to go into ServiceNow and search. This allows your engineers to spend longer working, and less time faffing around on the system.


Before I go any further, I have to give full credit to the Javascript Barcode/QR code generator to Jean-Baptiste Demonte and Jonathan Hourez. They are the guys who created the excellent barcode and QR code generator which I utilise here. The rest of the stuff from me is no where near as cool! But I’ll share anyway and hopefully you’ll like what you see…

So, the first thing is to go to the above link and download the source code for the Prototype Barcoder and copy and paste this into a UI script and call it ‘prototype-barcode’.

Next comes the UI Page:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<!-- Include the barcoder script first -->
<g:include_script src="prototype-barcode.jsdbx"/>
<g:evaluate jelly="true">
//Now build the URL for the asset using two sysparms which are expected in, sysparm_table and sysparm_sid
//We'll look at how these were passed in later in the UI Action
var baseURL = gs.getProperty('glide.servlet.uri');
var url = baseURL + '/nav_to.do?uri=' + jelly.sysparm_table + '.do?sys_id=' + jelly.sysparm_sid;
url;
</g:evaluate>
<!-- Populate a hidden field with the completed URL for easy referencing later -->
<input type="hidden" id="mydata" value="$[url]"/>
<!-- Build table with a couple of DIVs, and two buttons. One for printing and the other for closing the dialog -->
<table>
<tr>
<td colspan="2" >
<div id="container">
<div id="bcTarget" name="bcTarget"></div>
</div>
</td>
</tr>
<tr>
<td align="left">
<input type="button" onclick="printDiv('container');" value="Print Label"/>
</td>
<td align="right">
<input type="button" onclick="GlideDialogWindow.get().destroy();" value="Close Window"/>
</td>
</tr>
</table>
</j:jelly>

There are a few comments in the code above but essentially to summarise we do the following:
1) Include the prototype-barcode script
2) Build the URL for the record from the two passed in parameters and store this in a hidden input field
3) Build a table with an empty div to house the QR code when the time comes and two buttons. One closes the dialog page and the other calls a function called printDiv which we will compose in the Client Script section.

Ok, so now we need to build the QR code and the printing function.

To build the QR Code is done simply by using an onload event:

addLoadEvent( function() {
    //This one line takes in the value from the input field, and builds a QR code autoamtically
    $("bcTarget").barcode($('mydata').value, "datamatrix", {"moduleSize":10});
    //We then get the size of the div container of the QR code and resize the dialog window accordingly
    var width = $('bcTarget').getStyle('width');
    var dlg = GlideDialogWindow.get();
    dlg.setWidth(width);
    //Finally we centre it on screen
    dlg._centerOnScreen();
});

And finally the printDiv function gets defined here. Obviously when printing we don’t want to print the buttons. All we want is the QR Code so what we’re doing is essentially taking the HTML for the barcode, and opening a new blank window and writing this to that window. We set an onload event for it to print immediately.

function printDiv(divID) {
    //Get the width and height of the current barcode and add some padding to it
    var width = parseInt($('bcTarget').getStyle('width')) + 20;
    var height = GlideDialogWindow.get().getHeight();
    //Get the HTML contained within the container
    var divElements = document.getElementById(divID).innerHTML;
    //Find the centre of the screen and then open the window at this point
    var top = (screen.height/2) - (height/2);
    var left = (screen.width/2) - (width/2);
    var win = window.open('', 'print_content', 'width=' + width + ', height=' + height + ', top=' + top + ' ,left=' + left );
    win.document.open();
    //Write the HTML for the file including the onload window.print() method
    win.document.write('<html><body onLoad="window.print()">' + divElements + ' </body></html>');
    win.document.close();
    win.close();
    setTimeout( function() { win.close(); }, 3000);
}

That’s the end of the UI page and all the scripts. And finally, a few more lines for the UI Action and we’re all done. Create a new UI action which is shown on ‘Update’ only and ‘Client’.

Ensure it has an onclick function of ‘generateBar();’. Then all we need to do is define this function in the script as follows:

function generateBar() {
    //Generate a glidedialogwindow for the ui page above. And pass in the appropriate parameters
    var w = new GlideDialogWindow('barcode_gen');
    w.setTitle('Barcode Information');
    w.setPreference('sysparm_table', g_form.getTableName());
    w.setPreference('sysparm_sid', g_form.getUniqueValue());
    w.render();
}

That’s it! Told you it was simple!
Hit the link here for the update set. Feel free to leave comments below

15 Comments

  1. This is awesome. implemented in just a few minutes.

    Quick question though, would you know if it’s possible to remove the URL at the bottom of the print-out? I’d like to see this but with just the QR code itself as the URLs we’re generating are incredibly long and that’s making the end result a bit ugly.

    Like

  2. I just tried this and I get a barcode that is generated, but the code doesn’t scan. Any ideas why that might happen? If I input the URL into a QR generator on the web, it generates a QR code that does scan with no issue.

    Like

  3. Hey Ahmed,

    I’m getting the following error in the browser console after loading your update set and testing it with an incident ticket. I only see an “empty” popup and no QR code is generated. What could be the problem?

    Uncaught ReferenceError: jQuery is not defined VM4584:1298
    (anonymous function) VM4584:1298
    evalScript js_includes.jsx?v=12-30-2013_0526&lp=Mon_Jul_14_00_59_53_PDT_2014&c=2_36:86
    Class.create._evalScripts js_includes.jsx?v=12-30-2013_0526&lp=Mon_Jul_14_00_59_53_PDT_2014&c=2_36:22072
    Class.create._bodyRendered js_includes.jsx?v=12-30-2013_0526&lp=Mon_Jul_14_00_59_53_PDT_2014&c=2_36:21864
    (anonymous function) js_includes.jsx?v=12-30-2013_0526&lp=Mon_Jul_14_00_59_53_PDT_2014&c=2_36:10
    Class.create._responseReceived js_includes.jsx?v=12-30-2013_0526&lp=Mon_Jul_14_00_59_53_PDT_2014&c=2_36:13811
    Class.create._processReqChange js_includes.jsx?v=12-30-2013_0526&lp=Mon_Jul_14_00_59_53_PDT_2014&c=2_36:13689
    (anonymous function)

    Like

  4. sorry but it doesnt work for me. i got popup with empty QR. I got this error :
    GET https://dev12056.service-now.com/prototype-barcode.jsdbx?v=02-04-2016_1909&c=2_42 404 (Not Found)ajaxRequest @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:1018serverRequestWait @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:995Class.create._evalScripts @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:14821Class.create._bodyRendered @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:14614(anonymous function) @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:11Class.create._responseReceived @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:10715Class.create._processReqChange @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:10573(anonymous function) @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:11
    js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:14822Uncaught TypeError: Cannot read property ‘responseText’ of undefinedClass.create._evalScripts @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:14822Class.create._bodyRendered @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:14614(anonymous function) @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:11Class.create._responseReceived @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:10715Class.create._processReqChange @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:10573(anonymous function) @ js_includes_doctype.jsx?v=02-04-2016_1909&lp=Wed_Mar_16_03_01_06_PDT_2016&c=2_42:11
    navpage.jsx?v=02-04-2016_1909:90 added render event for ui_policy_onLoad

    Where did i wrong? where i can put onload event script?
    Is this “” the right one or this “”?

    Like

    • What do you mean more information?
      The QR code could technically store any text but it won’t automatically load the URL when scanning it as it will not be in a standard format.

      If you just want the location of the asset to be visible on the page, then in the UI action, you can add a w.sePreference(‘sysparm_location’, location) and in the UI page just add ${sysparm_location} wherever you want it to be displayed

      Like

      • hi, i’ve tried adding your suggestion but continue to return only the sysID instead of the location of the Asset record. i understand that it needs to be something like getReference to get the value and not the sysID but unable to get it to work.

        Any hints or tips? thanks for your help!

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s