Using cURL To Upload Files

Uploading files is fairly easy in SN but what if you need to upload a lot of files?

There are some solutions using the AttachmentCreator service which work great but I wondered if it was possible to do it without any programming at all. So I racked my brain then I remembered a tool: cURL.

cURL is a tool used for making all sorts of web related requests. The best part about is it a command line tool so if you are in need of automating web requests this is the tool to use. Theres several versions for every OS out there and its fairly well documented.

So lets take a look at how to use it…

If you haven’t already grab a copy of cURL from http://curl.haxx.se/

Logging in is a two step process, first we need to initialize our connection and set up a cookie:

curl --cookie-jar cjar -k -o output1.log --location "https://INSTANCE.service-now.com"

The –cookie-jar cjar parameter creates a cookie called cjar so that we can save our information

-k tells cURL to just accept any certificates that the site offers, this gets us by HTTPS if that’s enabled on your instance.

-o output1.log tells curl to output to a log file instead of the screen

–location tells curl to follow any redirects

Finally we put our instance URL.

Once you run this command and you have a cookie jar created you can attempt to log in.

curl --cookie cjar --cookie-jar cjar -k -o output2.log --data user_name=USERNAME --data user_password=PASSWORD --data ni.nolog.user_password=true --data ni.noecho.user_name=true --data ni.noecho.user_password=true --data remember_me=true --data screensize=1920x1080 --data sys_action=sysverb_login --location "https://INSTANCE.service-now.com/login.do"

This command reuses some of the same parameters but also specifies all the data used to log in. Just replace USERNAME, PASSWORD and INSTANCE and you should get a positive response back.

The way to check that everything is working properly is in the output files. If they return the code that would be the homepage you are golden.

Finally once you have your cookie and are logged in you can start uploading files.

curl --cookie cjar --cookie-jar cjar -k -o output3.log --location -F attachFile=@test.png "https://INSTANCE.service-now.com/sys_upload.do"

In this case I am uploading a PNG file called test that’s located in the same directory as cURL. If this is successful you will now be able to see the newly uploaded file on your instance.

Because this is an image file it will be available in the Image file browser but also at https://INSTANCE.service-now.com/scs/test.png or https://INSTANCE.service-now.com/test.pngx

Note: Theres also no need to keep logging in, once you are in you can continue to upload files.

If you’ve got tons of files no problem, just couple this technique with the `for` command (Windows Systems) and you can loop through all the files in a directory.

Heres a quick tutorial on that command: http://www.suite101.com/content/batch-file-programming-for-command-a37305

Simple Service Catalog Gallery

Here is a really simple Gallery View for Service Catalog built as an example for a fellow SN Developer.  It uses Jelly mostly and incorporates some jQuery for displaying details.

I have kept it very simple on purpose so it may be extended and changed to fit any needs.

Here is the Gist on GitHub.  Feel free to modify it however you need.  To install it  just create a UI Page and drop the contents in.

Service Catalog Gallery

Layout and Styling has been adapted from
http://cssdeck.com/labs/css-only-pinterest-style-columns-layout

Background is from
http://subtlepatterns.com/

 

ServiceNow Coding Style Part 2

So as a continuation to the previous article I want to expand the entire process of Coding Style with steps you can use in your own coding practices and as the basis of a Peer Code review process.

Step 0 – Installing Sublime (or another Smart Editor)

These instructions are set up for Sublime but are mostly tool agnostic as long as a similar plugin can be found.   This process will take a few minutes, but it will save you so much time I don’t think you will mind.  While it’s good to be aware of all the recommendations so you can use them naturally when you are coding, rely on tools as much as possible to automate code cleanup.

Grab Sublime from http://www.sublimetext.com/2 .  It’s $70 for a User License, but it’s worth every penny IMO.  You can evaluate it before you buy it to make sure it’s right for you.

Install the Sublime Package Control tool using the instructions from https://sublime.wbond.net/installation#st2.

Install node.js from http://nodejs.org/.  This is required for JSHint.

Install JSHint http://www.jshint.com/install/

Install the JSBeautify, DocBlocker, JSHint Sublime Plugins by opening Sublime and pressing Ctrl+Shift+P (Mac users figure this out on your own!) and typing “Package Control: Install Package”

When the Plugin window pops up start typing the name of the plugins, then press enter to install.

JSHint and JSBeautify both work on .js files, so to test create a test JS file with this content and press Ctrl+Alt+F to format it, and Ctrl+Alt+J to JSHint it.  If everything is installed correctly you should get a list of errors in the script.

function fakeFunction(name, cb, isBool) {
if(isBool==true){
cb(name)
}
Step 1 – Formatting

This refers back to the last post and is the first thing I usually look for in a code review.  Using JSBeautify makes this very simple, just run it, I accept most of the defaults, the only thing I might change is the indent_size setting to “4”.  All plugin settings can be tweaked in Sublime by going to Preferences > Package Settings > Package Name > Settings Default.  All changes should update immediately.

Step 2 – Naming Conventions

Avoiding poorly named variables, functions and records is essential to understanding code.  Properly named functions and variables make the code self-documenting and eliminate the need for many comments.  Here is a recap of the Coding Standards from the last article.

Variables – camelCase
Functions – camelCase
Private Functions – _camelCase
Classes – InitialsAreCapitals
Constants – ALL_CAPITALS
CSS Class – kebab-case
ServiceNow Records – PREFIX – Record Name
(for records that don’t use the name as a file name)
For UI Scripts it can be anything just no spaces.
For UI Macros I try to identify the usage like service_catalog_menu

Step 3 – JSHint Errors

JSHint will likely drive you insane with it’s complaining but it WILL make you a better coder and less dependent on JavaScript to ignore your mistakes.  To run it in Sublime you must save the file as .js

It will run automatically on Save or by pressing Ctrl+Alt+J

Certain things you can ignore are issues regarding using a function before it was defined, any complaints about ServiceNow specific objects not being declared (since they are global) and the error Do Not use JSON as a constructor.

Other than those exceptions I try to, and recommend you try to, fix all errors reported.  == versus === is very important to pay attention to because in MANY places === will break previously working functionality.  It is still best to use === and to explicitly compare types correctly or convert objects to strings before comparing.

It is most definitely more work NOW but it will save you headaches in the long run.

Step 4 – Engineering Principles

Two Principles that I mentioned before are DRY and SOC.  These should be applied when possible.  It is important to understand how to properly use ServiceNow to implement these principles.

Example – Within a series of business rules the same function is repeated and changed only slightly in each business rule.  The correct way to apply DRY in this case is to generalize the function so that the “tweaked” part is a parameter and then move that function to a Script Include.  It may even be possible at that point to move all the Business Rules to a single rule.

Example – Several reports were created as UI Pages that use the same basic layout but with just tweaked values.  In this case it may be best to either pass the parameters in the request OR to relocate the copied layout to a UI Macro and then include the macro.

Example – The same function is used within Client Scripts throughout the system.  In this case moving the function to a UI Script might be the best solution so the function is available to all Client Scripts.

The other principle I try to implement is Separation of Concerns.  This too goes back to understanding where all the code should be placed in ServiceNow.

Example - If styling is included directly in HTML  it is best to move that to a Style Sheet record and include that sheet.

Example – When working on a custom UI Page JavaScript to manipulate the DOM and make GlideRecord queries is mixed within functions.  This is definitely a bad way to do things, at the very least the code should be separated into functions whose intention is very specific.  At first glance, this may seem like just extra busy work, but the inevitably the application will grow, and if code is all separated by concern, it makes it easier to understand and re-use.

These principles are not hard rules, they need to be applied with some discretion.  If it is the 11th hour before a production push I would not recommend re-factoring all code into Script Includes.

Step 5 – ServiceNow Best Practices

This is a growing list of fixes or quirks within ServiceNow which just need to be memorized and looked for.  This list will update as I find and create more worst practices.

Do not use current.update() in onBefore Business Rules
Limit Synchronous GlideRecord Calls
Create functions in Business Rules and call them
Avoid nesting GlideRecords deeply
Don’t hardcode values; use Constants or System Properties
GlideRecords should check for next or hasNext before using them
All variables should be declared
A function should not be longer than one screen and ideally not even remotely that large
All paths in an AbstractAJAXProcessor Script Include should return a value
To get a GlideRecord field value, always use .toString() or .getDisplayValue()

Step 6 – Documentation

For all non-generated functions, like Client Scripts, I try to generate documentation.  This is not the same as comments, which should be used SPARINGLY.   Documentation states exactly what a function does, what it accepts as parameters and what it returns.  This is especially important in JavaScript because we don’t always know the type of parameters and returns.

To create a block like this, in your file right before a function you can type /** and enter.  This will automatically look at the function and pull out its parameters and returns and create the documentation for you.  I used an onChange function here for example but since they wont typically change parameters its not necessary to document each param, just the description.

/**

* Looks up the current caller and adds VIP styling
* and sets location based on the callers location
* @param {Object} control
* @param {String} oldValue
* @param {String} newValue
* @param {Boolean} isLoading
*/
function onChange(control, oldValue, newValue, isLoading) {
//…
}

If all of your code lives locally on your system, you will be able to create API documentation automatically with these blocks.

Local Files and Backup

I find it a best practice to store every file I work on locally.  Typically I will create a folder structure in a directory that is backed up to a service like Box.com.  The folder structure can mimic the table structure in ServiceNow, so a folder for sys_script_include, sys_script, sys_ui_script.  Or using friendly names Script Includes, Business Rules and so on.  Don’t get lazy here!  Keeping you files organized will speed things up in the future.

RemoteGlideRecord Revisited

So there was a request to bring back an old article on RemoteGlideRecord.  I am fairly certain ServiceNow will want to deprecate this Package.  I have tested the following in Eureka and it still works but I don’t know for how long.  Of course, even if you use this and it gets deprecated you always have the option of another integration type.

So what is RemoteGlideRecord?  It is a Package that allows you to use GlideRecord to query from one ServiceNow Instance to another.  If you are interested, behind the scenes this is executing a SOAP Request and uses Basic Authentication to authenticate to the second instance.

To create a basic instance of the Package use the following syntax.


var gr = new Packages.com.glide.communications.RemoteGlideRecord("https://INSTANCE.service-now.com", "TABLE");
gr.setBasicAuth("USER", "PASS");

 

Of course replace INSTANCE with your target instance, TABLE with the target TABLE and USER/PASS with the user and password.

WOAH!  Wait a second.  I don’t want to store my passwords in plain text in a script file!

Great point.  So here is an example of the Encrypter class.  You can encrypt and store passwords as properties and decrypt them when you need them.


var encrypter = new GlideEncrypter();
var encryptedPass = encrypter.encrypt("test");

gs.log("NEVER LOG PASSWORDS!");
gs.log( encrypter.decrypt(encryptedPass) );

 

Once we have the basic object set up the query can be executed.  Here is a sample of the code to run that query complete with some error checking to make sure the connection is valid.


if (gr.isValid()) {
gr.orderBy("number");
gr.query();

while (gr.next()) {
gs.print(gr.getValue("number"));
gs.print(gr.getDisplayValue("cmdb_ci"));
}

} else {
gs.print("not valid");
}

 

Notice that you cannot just dot.walk to the field name you must use getValue, getDisplayValue, getIntValue, getBooleanValue.

Likewise setting a value is done with setValue(field, value).

There are also a few configuration options which may or may not help you.

setAcceptGZIP(boolean) and setSendGZIP(boolean) obviously instruct the RemoteGlideRecord to send and receive GZIP.  This should be true.

setRedirectSupported(boolean) I can only assume tells RemoteGlideRecord to follow redirects, although I cannot test this theory.

setupProxy( host, port, user, pass ) seems like it can route the call through a proxy although I can think of no reason why that would ever happen.

setReturnDisplayValue(boolean) will turn of returning display values, if you aren’t planning on using them it can save some bytes off of what gets transferred.

setDebug(boolean) turns off and on debugging.  Off by default this will add invaluable log outputs that will definitely help if you don’t get connected straight away.

There is also a RemoteGlideAggregate which extends RemoteGlideRecord.  Seems to have the same methods as a standard GlideAggregate.  So there’s that to try as well.

Start using slack.com Now

Given that I work remotely most of the time I am quick to try new tools but very rarely does something change enough to provide a reason to change.  Over the years IM, Email and Yammer have held true while Mumble, IRC and others have failed.

Well today I finally signed up for slack.com, an enterprise communication platform, and I immediately realized the awesome potential.  The interface is clean and to the point but just beneath the surface are a ton of functions that either completely missing or practically unusable in other apps.  File sharing and code sharing were the two that jumped out immediately.  Then digging even more the integrations hooks caught my eye.

Of course this is ripe for integrating with ServiceNow so I took a stab at it.  Turned out to be incredibly easy.

Here I will walk you through setting up Slack with ServiceNow.

First set up a private test channel in Slack.  Then go to “+ Add a service integration”.  Towards the bottom is “Incoming WebHooks”

Add an Incoming WebHook and copy the WebHook URL that was generated.  Believe it or not we are already half done.

In ServiceNow create a new Outbound REST Web Message.  Set the REST Endpoint to that WebHook URL and Save.

Then go to the “post” function – actually this is the only one we need so you can remove the others.  In the Content field add the following:

{"text":"${text}"}

Add a REST Message Function Parameter and name it text and set the value to Hello World.

That’s it.  Run a test to make sure it works and you are good to start using the integration.

Now you may want to add additional configuration, such as setting the name and channel which you can do by adding more parameters into the Content field.  You can also configure these properties in Slack on the Integration details page.

Here’s an example with Username specified.  Don’t forget to add the Function Parameter.

{"text":"${text}","username":"${user}"}

So that’s a basic integration.  You can also build more complicated messages.  Here is one setup for sending out an Incident notification.


{
"fallback": "${fallback}",
"text": "${text}",
"pretext": "${pretext}",
"color": "${color}",
"fields": [{"title":"Priority","value":"${priority}","short":false},{"title":"Short Description","value":"${short_description}","short":false}]
}

slack

That’s it!  I wish they were all that easy.

 

Giving ServiceNow A Brain

In this, the first monthly project, I will be looking at trying to give ServiceNow the ability to automatically classify user input and suggest resolutions.

To start lets talk briefly about text classification.  I will say upfront that I am no expert in natural language processing.   I understand just enough to get myself in trouble.   For my purpose I will be using what is known as a Naive Bayes Classifier.

A super simple explanation is that based on some given data one can predict the probable output. This is done by creating a sort of map by training the system with previous data for which the output is already known.

The data that is important for text classification is word frequency and really anything that can be expressed in terms of data can be classified this way.

The intention will be to train the system based on a user input “description” and classify that text in a couple dimensions.  Possibly the type of resolution: Knowledge Base, Request, Incident and Category: Software, Hardware, Network and Topic.  The resulting classification will be fed into a ServiceNow application to make suggestions and automatically resolve the users issue if possible.

Since the libraries to do the classification are too large to bring them into ServiceNow I think the best solution would be to create a WebService Integration to a NodeJS app.  The integration will be able to add training data directly from ServiceNow and ask for a suggestion based on text.

The interface should accept users input and make suggestions which the user can accept or reject (and look for another solution.)  This could either be from the Ticket table or possibly a custom form, like a mock chat system.

Join me for the next post in this series where I will prototype the Node Service and Integration.  In the final post I will fully train the system and let end users try it.

sn_angular Project Started

After spending more time than I should have researching any out of box Angular directives that could be usable in custom pages I turned up not much.  There are some for the mobile interface but they are not created in a way that would be easily reusable.  I was also not sure if that would be changing so it would be a pretty unstable place to start.

Rather than wait I am starting my own project to recreate as much of the ServiceNow OOB features as Angular modules.

The project is located on github:
https://github.com/salcosta/sn_angular

It is also dependent on an earlier gist until I can merge everything into a single Update Set.

https://gist.github.com/salcosta/c68686e4e82c237dd627

 

Recreating The Form

The first step is to get a reliable model of the form fields.  Just using GlideRecord would not return enough information.  Remember we need all the attributes for a field, such as: type, mandatory, read only, length and so on.  This will allow us to create a fully functional form without having to do any custom coding.

To address this I have started ngGlideRecord which is meant to be a client callable Script Include which exposes a get function (meant to be like GlideRecord get) that returns a record with each fields full attributes.  For forms this will make it very easy to just iterate over the fields and output them immediately having access to all the attributes.

I also created a simple test UI Page that includes the core files and does a get for an Incident record (you’ll need to change the sys id if you try to recreate this test page).

The test page (which will eventually become a boilerplat and the Form Directive) has a simple switch to output the variable as an input text field if it is of type String.  The rest will just output the variable value.

Each type will eventually have a directive which recreates the standard ServiceNow functionality.

Be sure to watch the repository on github and check back here to get the latest.

Custom Element Pattern

Once a week I will try and publish some of my Patterns.  These will be reusable templates for everything from building apps to creating widgets.  This first week I am going to cover custom elements in forms using Formatters.  Be sure to check back weekly for new patterns.

Many times customers want custom functionality that goes beyond the standard form.  A UI Page is good but it requires the user to leave the form or have the content displayed in a pop-up.  Neither of these options are particularly appealing but there is another method which is not widely used, Formatters.

While this is a fairly common term thrown around I see few people actually using this method so here I will provide an overview (with code  of course) on how to implement various styles of custom formatters.

First a quick review of the process.  Start by creating a UI Macro, then navigate to the Formatters list and add a new one.  Each Formatter can link one UI Macro to one table.  You can create new Formatters if you want to link your macro to multiple tables.

The Name of the Formatter can be a friendly name of your new element.  The Table will be the target table to add the functionality to.  The Formatter is your actual UI Macro name with .xml appended to the end.  Since it is a “file name” your UI Macro should not contain spaces, it’s best practice to use an underscore in place of spaces.

Let’s start off easy with just a simple Formatter, adding an image to a form.

  1. Create a new UI Macro: my_image
  2. Add this to the body of the Macro between the Jelly tags
    <img src="http://replygif.net/i/1403.gif" />
  3. Create a new Formatter
    Name: My Image
    Table: Incident
    Formatter: my_image.xml
  4. Navigate to the Incident form and Personalize Form
  5. Add the My Image formatter to the form
    Formatters are usually located after the Fields in the List

If everything worked out you should have an image on your form.  This is not really a pattern yet but is still the basic way to get static information on a form.

Note: If you ever change the Formatter record (not the underlying UI Macro) you need to re-add it to the form.  

Now that we have gone through creating a basic Formatter let’s add some real functionality to it.  There are three patterns I’d like to walkthrough here: first is a custom Formatter that writes to a field and the second is a dynamic Formatter that displays a list and third is a completely client side Formatter.

Custom Field
This pattern creates a formatter that acts like a standard ServiceNow field, reading and writing to a field like normal.

  1. Create a new String field on a form ( I am using Incident for my examples).  The field should have a length of 100
  2. Once the field is added you want to make sure it is NOT displayed on the form since it would conflict with our Formatter
  3. Create a new UI Macro and add this to the body of the macro between the Jelly tags
    <table cellspacing="2" width="100%">
    <tbody>
    <tr>
    <td id="label.incident.u_custom" title="" data-type="label" choice="0" nowrap="true" class="label label_spacing" type="color">
    <span id="status.incident.u_custom" class="label_description" title="" mandatory="false" oclass="">$[SP]</span>
    <label for="u_custom" onclick="return labelClicked(this);" >Custom Element:</label>
    </td>
    <td>
    <input id="incident.u_custom" type="color" onchange="onChange('incident.u_custom');" name="incident.u_custom" value="$[current.u_custom]" autocomplete="off" />
    </td>
    </tr>
    </tbody>
    </table>
  4. Replace u_custom with the name of your new field and incident with whichever form you are working on.
  5. Create a Formatter, Personalize your form and add the new Formatter

You now should have a custom Color Picker element that acts like a ServiceNow field.

Custom Dynamic List
This pattern demonstrates creating a custom list view based on the current record.

  1. Create a New UI Macro and add this as the body of the Macro between the Jelly Tags
    <g2:evaluate>var sys_id = RP.getParameterValue('sys_id').toString();
    var auditRec = new GlideRecord('sys_audit');
    auditRec.addQuery('tablename', 'incident' );
    auditRec.addQuery('documentkey', sys_id );
    auditRec.query();
    var canViewAudit = gs.getSession().getRoles().toString().indexOf("admin") != -1;
    var row_class = "list_odd";
    </g2:evaluate><br/>
    
    <j2:if test="$[canViewAudit]">
    <table style="width:50%">
    <thead>
    <tr class="header">
    <td class="column_head">User</td>
    <td class="column_head">Date</td>
    <td class="column_head">Field</td>
    <td class="column_head">Previous Value</td>
    </tr>
    </thead>
    
    <j2:while test="$[auditRec.next()]">
    <tr class="list_row $[row_class]">
    <td>$[auditRec.user.toString()]</td>
    <td>$[auditRec.sys_created_on.getDisplayValue()]</td>
    <td>$[auditRec.fieldname.toString()]</td>
    <td>$[auditRec.oldvalue.toString()]</td>
    </tr>
    
    <g2:evaluate>
    if( row_class == "list_odd" ){
    row_class = "list_even";
    } else {
    row_class = "list_odd";
    }
    </g2:evaluate>
    </j2:while>
    </table>
    </j2:if>
    <j2:if test="$[canViewAudit==false]">
    <p>$[SP]Audit View is Only viewable by Administrators</p>
    </j2:if>
    
  2. If you are using a form other than incident change it in the script
    This could be generalized to just grab the table name and be applicable to any table
  3. Create the Formatter and add it to the form.

You should now have an Audit list that will display for Admins.   If nothing is showing up make sure auditing is turned on for the table and a change is made.

Client Side Element
This pattern is the most “wide open” in terms of what can be done.  In this example I will recreate the Short Description field but dynamically.  One key thing to keep in mind is the “dynamic” part here refers to performing some AJAX operation.  These calls should always be asynchronous and not block the User.

  1. Create a new UI Macro and add this to the Macro body between the Jelly tags
    <table cellspacing="2" width="100%">
    <tbody>
    <tr>
    <td choice="0" nowrap="true" class="label label_spacing" type="color">
    <label for="dynamic_custom">Short Description:</label>
    </td>
    <td>
    <input id="dynamic_custom" type="text"/>
    </td>
    </tr>
    </tbody>
    </table>
    <script src="https://code.jquery.com/jquery-2.1.1.min.js" />
    <script>
    jQuery.noConflict();(function($){var sys_id = gel('sys_uniqueValue').value;
    
    getDynamicValue();
    
    function getDynamicValue(){
    var incidentRec = new GlideRecord('incident');
    incidentRec.addQuery('sys_id', sys_id);
    
    incidentRec.query( function( incidentRec ){
    if( incidentRec.next() ){
    $("#dynamic_custom").val( incidentRec.short_description.toUpperCase() );
    }
    })
    
    }
    
    })(jQuery)
    </script>
  2. Change references to incident to whichever table you are using
  3. Create the Formatter and add it to the form

When the form loads it will dynamically fetch the Short Description and fill it in.  Keep in mind this is read only, but you could combine this pattern with the others to create that link.

Obviously in practice you will want to do more than get the Short Description and you really are not limited.  You may load in your UI Macro any JavaScript library so I have used this same method combined with DataTables, Handlebars, AngularJS and many more libraries to create rich functionality.

You may also use this technique to load data via Web Service dynamically, creating the effect of having all data from external systems within a ServiceNow form without needing to store it.

Almost every custom element derives from these patterns, if I come up with more I will be sure to share and am interested in seeing what everyone else comes up with!

Generate an Angular Service from a Script Include

I figured I would dedicate Fridays to Angular and Jelly articles, first up here is generating an Angular Service automatically from a Script Include.

You might be tempted to just put GlideAjax calls right within your Angular Controller but that’s bad.  It clutters your controller and if you ever need to use that same function you would need to copy and paste that code.  On the other hand if all you need to do is create a Service that calls a Script Include it makes no sense to create UI Scripts for each that all essentially do the same thing.  To me this is not a problem but a chance to simplify creation of these Services by using a Processor.

To start I need to programatically extract the functions and parameters from a given Script Include.  Initially I thought a Regular Expression might work but it’s not a good solution.  Instead I chose to use Esprima to generate an Abstract Syntax Tree (a sort of representation of the code as a tree) and use that to find functions and parameters.

Esprima (http://esprima.org) actually loads right into ServiceNow as a Script Include without any issues.   Once loaded you can just include that Script Include and create syntax trees from any code in the system.

I created a Processor which generates an AST from a Script Include.  I look through the AST to find the main object (the one that is assigned to a variable of the same name as the Script Include) and then looked through that object for functions.

Each function not prefixed with _ is expected to be a public function and will be added to the returned Angular Service.

Within the body of that function if I find any assignments that have “getParameter” in the expression I pull out the name and use that as a parameter for the Angular Service method.

I also included a function to parse the XML response that is automatically called when the response comes back from ServiceNow.

Now for any Script Include, which extends AbstractAjaxProcessor, I can link to my processor which will generate an Angular Service with all the functions from the Script Include automatically.  I can inject that service into my apps controllers and call the functions as if they were on the client side.

Instead of using GlideAjax I use the Angular $http provider which returns a promise object.  So when you use the result of the function call you must do so through a `then` function.  Check out the examples below to see this in action.

github:gist https://gist.github.com/salcosta/c68686e4e82c237dd627


Example

The Angular Service that should be generated from this Script Include should have 2 methods with one accepting `sysparm_sys_id` as a parameter.

var IncidentTest= Class.create();

IncidentTest.prototype = Object.extendsObject(AbstractAjaxProcessor, {

getIncidents : function(){
var sys_id = this.getParameter("sysparm_sys_id").toString().toString();

return sys_id
},

getIncidents2 : function(){
return "test"
}

});

Here is the example output that would be generated.


angular.module('IncidentTestService', []).factory('IncidentTestServ', ['$http', function($http) {

return {
config : { headers: {'Accept' : '*/*', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8','X-UserToken': g_ck } },
url : 'xmlhttp.do',

getIncidents : function ( sysparm_sys_id ){
var data = 'sysparm_processor=IncidentTest&sysparm_name=getIncidents&ni.nolog.x_referer=ignore&x_referer=home.do&sysparm_sys_id=' + sysparm_sys_id + ''

return $http.post( this.url , data , this.config ).then( getAnswer );
},

getIncidents2 : function ( ){
var data = 'sysparm_processor=IncidentTest&sysparm_name=getIncidents2&ni.nolog.x_referer=ignore&x_referer=home.do'

return $http.post( this.url , data , this.config ).then( getAnswer );
}
}

}]);

Here’s a sample usage in a UI Page.

HTML

<script src="IncidentTest?ng-service"></script>

Script

angular.module("Inventory",['InventoryCtrl','IncidentTestService']);

angular.module("InventoryCtrl",[]).controller("InventoryController", ['$scope', 'IncidentTestServ', function($scope, IncidentTestService){
IncidentTestService.getIncidents("Test").then(function(res){
console.log(res)
});
}]);

ServiceNow Coding Style Guide Part 1

I thought I would kick of this new blog with a topic that is very important to me,  Coding Style in ServiceNow.  Here I will present a short list of rules and principles to guide your coding.

Following this guide will make your code more readable which will make maintaining the code much easier.  That means less time trying to decipher your or co-workers code and lower costs to maintain code.  This is true of any code base but especially in ServiceNow where the developer ecosystem is so varied.

The end goal is to have all code appear to be written by a single person.

Once a good track record can be established on following these practices then you can start to introduce higher level concepts and principles.  More on those in future articles.

Personally, I disagree with long style guides and best practices documents.  If there are too many rules to start it is impractical for new developers to follow them all.  My approach is to start with the fundamentals.  Once they are mastered then you can layer in more advanced practices.  So for now I am keeping the list short. (It should fit on an index card)

Naming
Functions should be named like verbNoun, using camel case. This will make it easier to remember as well as forcing the function to perform a specific purpose.

Variables should not have abbreviations, ever.  It is preferable to use camel case when creating variables although underscores have started to be used instead.  It does increase readability but most existing code will not follow this.

Classes should always be camel case with the first initial capitalized.

Constants should be all upper case.

All record names should follow a convention.  I prefer Prefix – Script Name, where the prefix is the company name or application name.  This is applicable only where the record name is not the script name such as on Business Rules and Client Scripts.

Script Includes should follow the same convention as classes.  UI Scripts should be all lower case using underscores to separate words.

Formatting
There are two options for brackets, same line or not.  I prefer same line.  As long as you are consistent it is a matter of opinion

Whitespace should be used liberally to increase readability.  I favor using spaces within parentheses.  Line breaks to separate blocks of code within functions and two line breaks between functions.

Edit:  I am going to post this in a new article but I have started not to do this.  Instead I am following the standard of putting spaces outside of the parens.  Which seems just as readable.

Indentation should be 2 or 4 spaces but be consistent.

Semicolons should always be used.

Commenting
By all means, if you feel your code is to complicated use comments to clarify, but before you do that ask, “Can I rewrite this to make it clearer?”  If the answer is yes, rewrite the section and see if the comment is still necessary.  The goal is for the code to document itself.

Odds and Ends
Always use === instead of == to compare values.  This will prevent accidental coercion of variables.

Try and use ‘ instead of ”

Avoid ternary operators

Avoid eval

Principles
Don’t Repeat Yourself.  If you find yourself writing the same code over and over generalize it and move it to a separate function.

Never just copy and paste code.  Always rewrite it and try to understand line by line what it’s doing.  While it’s tempting to just inject a bunch of functionality, that is not going to help if there is an error or you need to modify the code.

Try to keep your code separated by intention.  For instance don’t have a single function that does a database call and then immediately updates the UI.  This is called Separation of Concerns and is the basis for other more specific principles like MVC.  Separated code will make it easier to update and reuse.

Finally, care about your craft.  Your code will likely never hang in a museum but the functionality that you are building matters to your users and it should matter to you as well.

Bonus Cheat Sheet!

Cheat Sheet
Coding Style Guide Part 1 Cheat Sheet