Attachment Transfer: Moving Files from HTML Input to ServiceNow Records
Ever got a requirement to create a UI based form such as on widget/UI page when the user needs to attach a file and same needs to be transferred to a ServiceNow form.
Use Case: A request is awaiting approval but the approver is on vacation and has formally approved via email on the reminder sent by Agent. Since the Agent has the approval now, it needs the functionality to override the approval on behalf of the approver.
Here is a quick demo of the utility how it works.
There can be certain number of ways to achieve this. Let us try to follow this one.
UI Action
Create the UI Action with following details.
Name: Override Approval
Form Button: true
Action Name: override_approval
Client: true
Condition: <as needed per requirement>
onClick: approvalOverride()
Script:
function approvalOverride() {
var dialogClass = GlideModal ? GlideModal : GlideDialogWindow;
var dialog = new dialogClass('override_approval');
dialog.setTitle('Please provide the reason for Overriding Approval');
dialog.setPreference("onPromptComplete", function(attFile, work_note) {
var file = attFile.files[0],
reader = new FileReader();
reader.onload = function () {
var b64 = reader.result.replace(/^data:.+;base64,/, '');
var fileName = attFile.files[0].name;
var contentType = attFile.files[0].type;
var ritmID = g_form.getUniqueValue();
var attAjax = new GlideAjax('AttHandler');
attAjax.addParam('sysparm_name', 'attachToRITM');
attAjax.addParam('sysparm_ritm_id', ritmID);
attAjax.addParam('sysparm_fileName', fileName);
attAjax.addParam('sysparm_contentType', contentType);
attAjax.addParam('sysparm_base64Encodedcontent', b64);
attAjax.addParam('sysparm_work_note', work_note);
attAjax.getXML(updateRITM);
};
reader.readAsDataURL(file);
});
dialog.render();
}
function updateRITM(response){
location.reload();
}
UI Page
HTML:
<style>
.dialog_content {
width: 100%;
height: 100px;
vertical-align: middle;
min-width: 300px;
padding: 0 10px 10px 10px;
}
.dialog_buttons {
display: inline;
text-align: right;
vertical-align:bottom;
white-space: nowrap;
}
th, td {
padding: 5px;
}
</style>
<g:ui_form onsubmit="return invokePromptCallBack();">
<table border="0" width="100%">
<tr>
<td>
<label for="attFile">Select a file:</label>
<input type="file" id="attFile" name="attFile" />
</td>
</tr>
<tr>
<td>
<label for="work_note">Work Notes:</label>
<input id="work_note" class="col-sm-12 form-control" type="text" name="work_note" required="true" placeholder="Work Notes"/>
</td>
</tr>
<tr>
<td class="dialog_buttons">
<g:dialog_button
id="${jvar_ok_id}"
type="button"
onclick="invokePromptCallBack('ok');"
style="width: 10em;padding:5px;float:right">${gs.getMessage('Override Approval')}
</g:dialog_button>
</td>
<td class="dialog_buttons">
<g:dialog_button
id="${jvar_ok_id}"
type="button"
onclick="invokePromptCallBack('cancel')"
style="width: 5em;padding:5px;float:right">${gs.getMessage('Cancel')}
</g:dialog_button>
</td>
</tr>
</table>
</g:ui_form>
Client Script:
function invokePromptCallBack(type) {
var file = document.getElementById('attFile');
if (type == 'ok' && (file.files.length == 0 || !gel('work_note').value)) {
alert('Please provide both Attachment and Work Notes');
return;
}
var gdw = new GlideDialogWindow.get();
if (type == 'ok') {
var f = gdw.getPreference('onPromptComplete');
if (typeof(f) == 'function') {
try {
f.call(gdw, file, gel('work_note').value);
} catch (e) {}
}
}
gdw.destroy();
return false;
}
Script Include:
Name: AttHandler
Description: Attachment handler for copying attachment from HTML input to forms and records
Client Callable: true
Script:
var AttHandler = Class.create();
AttHandler.prototype = Object.extendsObject(AbstractAjaxProcessor, {
attachToRITM: function() {
var ritmID = this.getParameter('sysparm_ritm_id');
var fileName = this.getParameter('sysparm_fileName');
var contentType = this.getParameter('sysparm_contentType');
var base64Encodedcontent = this.getParameter('sysparm_base64Encodedcontent');
var workNotes = this.getParameter('sysparm_work_note');
var ritmGR= new GlideRecord("sc_req_item");
if (ritmGR.get(ritmID)) {
var attachmentDocGR = new GlideSysAttachment();
var attachmentStream = GlideStringUtil.base64DecodeAsBytes(base64Encodedcontent);
attachmentDocGR.write(ritmGR, fileName, contentType, attachmentStream);
ritmGR.work_notes = workNotes;
ritmGR.update();
}
return '';
},
type: 'AttHandler'
});
Following the above steps would be able to assist you copying the attachment from UI page/Widget or any HTML input to ServiceNow Forms. You can further add the code to update the approval records and respective fields on RITM as per this use case.
Please note this configuration is not validated for Workspace as of now, will keep you posted once workspace compatible functionality will be done.
A very special mention to Rishikesh who has worked on this implementation, please take out some time to read his article on ChatGPT Intelligent Document Retrieval in ServiceNow.
Happy Learning!!!
Follow me on Linkedin