How to add an attachment to a record using a file input on a UI Page (custom development).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-11-2022 01:10 PM
I have a form on a UI page and all I need to do is take an input field with type "file", and have the user upload a file. Simple enough.
The file then needs to be added to a record as an attachment. I have the record in the form.
I can't figure out how to add the file as an attachment, I have tried GlideSysAttachment().
var fileName = this.getParameter('sysparm_file_name'); //file name from input
var fileType = this.getParameter('sysparm_file_type'); //file type
var tableName = this.getParameter('sysparm_table_name'); //the table of the record
var task = this.getParameter('sysparm_task'); //the record
var attachment = new GlideSysAttachment();
var rec = new GlideRecord(tableName);
rec.get(task);
var file = fileName;
var contentType = fileType;
var content = ""; //I am unsure if I can put anything here?
var agr = attachment.write(rec, file, contentType, content);
return agr;
I am unsure as to if this will work with file types.
I have tried the api/now/attachment/file end point to POST.
/api/now/attachment/file?table_name=" + tableName + "&table_sys_id=" + task + "&file_name=" + fileName
But this doesn't seem to work either.
I have to use a input element with type file in the UI page.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-11-2022 07:00 PM
Hi @nick0989
If you want to keep it all client side and use the Attachment API, the input when used as type file will return a Files array of File objects. You can use the File object with the Attachment API "Uploading a file with a Binary Request".
Here's a basic example:
//Client Script of UI Page
//create an event listener on change
upFile.addEventListener('change', attachFiles, false)
//file handler callback for the event listener
function attachFiles(evt){
//get the name of the first File object
var filename = evt.target.files[0].name;
//get the content type of the first File object
var contentType = evt.target.files[0].type;
//Passing the values to the html view
fname.innerText = "File Name: " + filename;
type.innerText = "Content Type: " + contentType;
//Using xmlhttp request (you might have to send Creds).. You could also use the REST Message Web Services in ServiceNow alternatively
//setting up the url with params
var url = "/api/now/attachment/file?file_name=" + filename + "&table_name=incident&table_sys_id=";
//I'm just grabbing a task record. You don't have to do this step if you already have the sys_id and know the table
var incGr = new GlideRecord('incident');
incGr.setLimit(1);
incGr.query(function(incGr){
if(incGr.next()){
//adding sysid of record to my params
url += incGr.sys_id + "";
var oReq = new XMLHttpRequest();
oReq.open("POST", url, true);
oReq.onload = function (oEvent) {
// If you reach here it is successfully Uploaded.
//just printing out to my html view the details
var span = document.createElement('span');
span.innerText = "File uploaded successfully to ";
var anchor = document.createElement('a');
anchor.href = '/incident.do?sys_id=' + incGr.sys_id;
anchor.innerText = incGr.number.toString();
span.appendChild(anchor);
fdata.appendChild(span);
};
//send the request passing in the one file object
oReq.send(evt.target.files[0]);
}
});
}
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<!-- UI Page HTML -->
<form>
<label>Upload File</label>
<input id="upFile" type="file" />
</form>
<section>
<p id="fname"></p>
<p id="type"></p>
<p id="fdata"></p>
</section>
</j:jelly>
If you wanted to send via Server Side, one way to get the file contents from an uploaded file through the input element is using the Web FileReader API: https://developer.mozilla.org/en-US/docs/Web/API/FileReader
Basically in the Event listener instead of sending the file, create an instance of the FileReader and onload of the file grab the contents through the target result. Note: The example below will be plain text but the API has different methods for different types of data.
Using same HTML markup but a slightly modified script to capture the file content.
upFile.addEventListener('change', attachFiles, false)
function attachFiles(evt){
var filename = evt.target.files[0].name;
var contentType = evt.target.files[0].type;
//Create an instance of FileReader
var fileR = new FileReader();
//passing values to html view
fname.innerText = "File Name: " + filename;
type.innerText = "Content Type: " + contentType;
//add listener on file reader for the load of file content
fileR.onload = function(e){
//get file content
var content = e.target.result;
//pass contents to the HTML view
var span = document.createElement('span');
span.innerText = "File content: \n" + content;
fdata.appendChild(span);
};
fileR.readAsBinaryString(evt.target.files[0]);
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-11-2022 07:54 PM
Thanks, i'll give this a shot in the morning.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-16-2022 07:37 AM
I was able to try your approach yesterday and I kept trying but I could only upload one file to the record. Not multiple files. Here is what I had set:
var xhr = new XMLHttpRequest();
var url = [];
//files is just the input type="file" with multiple attribute.
for (var i = 0; i < files.length; i++) {
url.push({
apiEndpoint: "/api/now/attachment/file?file_name=" + files[i].name + "&table_name=" + table + "&table_sys_id=" + record,
file: files[i]
})
}
url.forEach(function(item){
xhr.open("POST", item.apiEndpoint, true);
xhr.send(item.file);
})
I read the attachment API and it says it only works for one file upload. I thought maybe if I could create a loop and store the URL then loop through it, that it would make multiple calls. This does not seem to work though.
Any suggestions for attaching multiple images?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-17-2022 09:38 AM
That looks like it should work. I've done it many times before. I'll take a look and get back to you.