How to get the size of an attachment on a record producer?

David Lundy
Tera Contributor

I'm creating records for a photo album application.  I'm using a record producer to generate the album.  Part of the requirements is that all attached files must be JPG/JPEG/PNG formats AND be less than 10mb in size.

 

I've figured out how to identify the file extensions using the following code on a Catalog Client Script (onSubmit):

function onSubmit() {
    var numAtt = this.document.getElementsByClassName('get-attachment').length; // get # of attachments
    for (i = 0; i < numAtt; i++) { // iterate through all attachments
        var value = (this.document.getElementsByClassName('get-attachment')[i].innerHTML).toLowerCase(); // convert string to lowercase so we can test the extension
        if ((value.indexOf('.jpg') == -1 && value.indexOf('.jpeg') == -1 && value.indexOf('.png') == -1)) { // look for the desired file extensions and return true if NONE of them are found
            alert("*** Attachments should only be in jpg/jpeg/png format!"); // warn user of unacceptable file types
            return false; // stop the submission process until the file attachment situation is resolved
        }
    }
}
Unfortunately, I cannot figure out how to get the size of the attachments via the 'get-attachment' method.  Are the available attributes documented somewhere?
Thanks in advance for any help that can be offered.
1 ACCEPTED SOLUTION

Nick Parsons
Mega Sage

I'll suggest two ways, both require a little bit of reliance on the DOM, but it's better than trying to parse your inner HTML:

Inspect the Angular Scope of the attachment

As you may know, the portal is made up of angular widgets. Different widgets and parts of your page have scopes, which you can tap into using the angular object. This means you can inspect the scope/data that the attachment widget is using to get details about the data it's looking at. For example running the below in a client script will give you an array of attachments:

 

this.angular.element("#sc_cat_item").scope().attachments

 

The array is an array of objects which look like so that represent each attachment:

 

[
  {
    "ext": "jpg",
    "thumbnail": "fac19ae853e2121236a838f0a0490e22.iix?t=medium",
    "size_bytes": "1.8 MB", // not always "MB", can be in other units like "KB"
    "file_name": "rafael-garcin-XeQ-BG3SSfk-unsplash.jpg",
    "sys_updated_on_display": "2024-11-08 10:08:50",
    "sys_created_by_display": "System Administrator",
    "canWrite": true,
    "sys_updated_on": "2024-11-07 23:08:50",
    "thumbSrc": "fac19ae853e2121236a838f0a0490e22.iix?t=medium",
    "table_name": "incident",
    "sys_id": "fbd08ae853f1121036a838f0a0490e22", // sys_id of the attachment
    "content_type": "image/jpeg",
    "size": "1.8 MB",
    "sys_created_on": "2024-11-07 23:08:48",
    "canDelete": true,
    "table_sys_id": "02a556185371521036a838f0a0490e39", // sys_id of the record that will be created
    "state": "available",
    "thumb_src": "fbd08ae853f1121036a838f0a0490e22.iix?t=medium",
    "sys_created_by": "admin",
    "viewImage": false,
    "trackByKey": "fbd08ae853f1121036a838f0a0490e22availablerafael-garcin-XeQ-BG3SSfk-unsplash.jpgfalse"
  },
  ...
]

 

From the above, you can use the  size_bytes to do you size calculation, although you'll need to use some logic to handle the different units as its not always consistent, and can show KB, etc. You can also use the above approach to get the extension from the ext property to see if it's one of your allowed ones.

 

Make a GlideAjax call to query the attachment table

You may have noticed that the above array of objects also provides a table_sys_id. This represents the sys_id of the record that is going to be created when you hit "submit". That's right, ServiceNow pre-generates the sys_id of the record is going to create even before you hit submit! That allows it to associate attachments to the record it'll create. You can either use the above approach to get that sys_id, but that's a bit finicky since it's part of an array of objects. Instead, you can get the target sys_id / table via looking at different properties in the Angular Scope chain: 

 

var $scope = this.angular.element("#sc_cat_item").scope();
var toBeRecordTable = $scope.data._attachmentTable;
var toBeRecordSysId = $scope.data._generatedItemGUID;
// make a GlideAjax call to look at and add the sys_attachment table's `size_bytes` where table_sys_id and table_name match the above variables.

 

I'll note that asynchronously aborting an `onSubmit` is not easily done, so this solution has another roadblock that you need to get over. The approach I've seen is to always return false from your onSubmit function, and then in the callback of your GlideAjax call, use g_form.submit(); if the response is all good.   

View solution in original post

5 REPLIES 5

David Lundy
Tera Contributor

Thanks @Nick Parsons!  You've got me going in the right direction now!  I'm not getting results from my query of sys_attachment, but I'll work through that.  I appreciate the help!