In this blog, we will show how to create HTML web resource in the form and how to display those attachments in the timeline

For creating this, I have used accounts table in dynamics 365.

Open your solution and go to the Web Resources and create a HTML Type Web Resource and Add your code in the Text Editor

Next, open your form from the entity and add a new one column tab from Insert.

Next Add Timeline in the tab

Next add Web Resource under the Timeline

Next save and publish the form

Now Check this is working or not in your App

Code

<html><head>
<title>Upload Multifile Attachments to Dynamics 365 Notes Entity</title>
<meta charset=”utf-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1″>
<script src=”path/to/setEmailRange.js”></script>
<script src=”ClientGlobalContext.js.aspx” type=”text/javascript”></script>
<script src=”https://code.jquery.com/jquery-3.6.0.min.js”></script>
<link rel=”stylesheet” href=”https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css”>

<meta><meta><meta><meta><meta><meta><meta><meta><meta></head>
<body onfocusout=”parent.setEmailRange();” style=”overflow-wrap: break-word;”>
<input type=”file” id=”attachments” multiple=””>
<button id=”upload”>Upload</button>
<div id=”attachmentsList” style=”font-family: undefined;”></div>

<script>
$(document).ready(function () {
var storedAttachments = getStoredAttachments();
storedAttachments.forEach(function(attachment) {
addAttachmentToList(attachment[“filename”], attachment[“annotationid”]);
});

$(‘#upload’).click(function () {
debugger;
var files = $(‘#attachments’)[0].files;
var entityId = Xrm.Page.data.entity.getId().replace(‘{‘, ”).replace(‘}’, ”);
var count = 0;

function uploadFile() {
debugger;
if (count < files.length) {
var file = files[count];
var reader = new FileReader();
reader.onload = function (e) {
var fileContent = e.target.result;
var fileName = file.name;
var fileExtension = fileName.split(‘.’).pop();
var fileSize = file.size;
var mimeType = file.type;
var note = {
“subject”: fileName,
“documentbody”: fileContent,
“filename”: fileName,
“mimetype”: mimeType,
“filesize”: fileSize,
“isdocument”: true,
“objectid_account@odata.bind”: “/accounts(” + entityId + “)”
};
createNoteWithAttachmentId(note, function (attachmentId) {
debugger;
addAttachmentToList(fileName, attachmentId);
count++;
setTimeout(uploadFile, 1000);
});
};

reader.readAsDataURL(file);
debugger;
}
}

uploadFile();
});
});

function createNoteWithAttachmentId(note, callback) {
var req = new XMLHttpRequest();
debugger;
req.open(“POST”, Xrm.Page.context.getClientUrl() + “/api/data/v9.1/annotations”, false);
req.setRequestHeader(“Accept”, “application/json”);
req.setRequestHeader(“Content-Type”, “application/json; charset=utf-8”);
req.onreadystatechange = function () {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 204) {
var uri = req.getResponseHeader(“OData-EntityId”);
var regExp = /\(([^)]+)\)/;
var matches = regExp.exec(uri);
var newEntityId = matches[1];
console.log(“Note created successfully with attachment ID: ” + newEntityId);
//alert(“Note created successfully with attachment ID: ” + newEntityId);
callback(newEntityId);
} else {
console.log(“Note creation failed.”);
//alert(“Note creation failed.”);
}
}
};
req.send(JSON.stringify(note));
debugger;
}


function addAttachmentToList(fileName, attachmentId) {
debugger;
var listItem = document.createElement(‘li’);

// Create attachment link
var attachmentLink = document.createElement(‘a’);
attachmentLink.href = Xrm.Page.context.getClientUrl() + “/api/data/v9.1/annotations(” + attachmentId + “)/documentbody”;
attachmentLink.innerText = fileName;
attachmentLink.download = fileName;
listItem.appendChild(attachmentLink);

// Create delete icon
var deleteIcon = document.createElement(‘i’);
deleteIcon.className = “fa fa-trash”;
deleteIcon.style.marginLeft = “10px”;
deleteIcon.addEventListener(“click”, function() {
deleteNoteAttachment(attachmentId, function() {
listItem.parentNode.removeChild(listItem);
var storedAttachments = getStoredAttachments();
storedAttachments = storedAttachments.filter(function(attachment) {
return attachment.attachmentId !== attachmentId;
});
localStorage.setItem(‘attachmentsList’, JSON.stringify(storedAttachments));
});
});
listItem.appendChild(deleteIcon);

document.getElementById(‘attachmentsList’).appendChild(listItem);

// Store the new attachment in local storage
var storedAttachments = getStoredAttachments();
storedAttachments.push({
fileName: fileName,
attachmentId: attachmentId
});
localStorage.setItem(‘attachmentsList’, JSON.stringify(storedAttachments));
}

function deleteNoteAttachment(attachmentId, callback) {
debugger;
var req = new XMLHttpRequest();
req.open(“DELETE”, Xrm.Page.context.getClientUrl() + “/api/data/v9.1/annotations(” + attachmentId + “)”, false);
req.setRequestHeader(“Accept”, “application/json”);
req.setRequestHeader(“Content-Type”, “application/json; charset=utf-8”);
req.onreadystatechange = function () {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 204) {
console.log(“Note attachment deleted successfully.”);
callback();
} else {
console.log(“Note attachment deletion failed.”);
}
}
};
req.send();
}
function getStoredAttachments() {
debugger;
var attachment = null;
var entityId = Xrm.Page.data.entity.getId().replace(‘{‘, ”).replace(‘}’, ”);
var url = Xrm.Utility.getGlobalContext().getClientUrl() + “/api/data/v9.2/annotations?$select=annotationid,filename&$filter=_objectid_value eq ” + entityId;
var req = new XMLHttpRequest();
req.open(“GET”, url, false);
req.setRequestHeader(“OData-MaxVersion”, “4.0”);
req.setRequestHeader(“OData-Version”, “4.0”);
req.setRequestHeader(“Content-Type”, “application/json; charset=utf-8”);
req.setRequestHeader(“Accept”, “application/json”);
req.setRequestHeader(“Prefer”, “odata.include-annotations=*”);
req.onreadystatechange = function () {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var results = JSON.parse(this.response);
attachment = results.value;
console.log(results);
// for (var i = 0; i < results.value.length; i++) {
// var result = results.value[i];
// Columns
// var annotationid = result[“annotationid”]; // Guid
// var filename = result[“filename”]; // Text
// }
} else {
console.log(this.responseText);
}
}
};
req.send();
return attachment;
/* var storedAttachments = localStorage.getItem(‘attachmentsList’);
if (storedAttachments) {
return JSON.parse(storedAttachments);
} else {
return [];
} */
}


</script>
</body></html>

For any Help or Queries Contact us on info@crmonce.com or +918096556344