Assume you have a SharePoint form with a lot of input fields as well as the option to append attachments to the list item. Assume one of your users accidentally tries to attach the same file twice (or two separate files with the same name) to the list item. When submitting the form, the following exception is displayed:
Failed to get value of the "Attachments" column from the "Attachments" field type control. See details in log. Exception message: A file with the name already exists.
Note: the reason behind this error is that attachments in SharePoint are stored in individual folders by the item Id (for example, attachments of item with Id 34 of list YourList are stored in folder /lists/YourList/Attachments/34) and you cannot store multiple files within the same folder. This is different as the attachment handling with mails, where you can attach multiple files with the same name without any errors.
You can imagine the frustration of the user, as all of the data typed into the form was lost. Wouldn’t it be better not to allow the user to choose a file to attach if a file with the same name was already attached to the item? Definitely it would be far better, and it is quite simply to fulfill using jQuery.
To be able to perform the validation, first we have to understand, how the name of the attachments are store on the page. Assume a file called test1.txt is already attached to the item, and in this editing session we chose the file called test2.txt (from the path c:\temp) to be attached (as display below).
In this case, the HTML DOM of the page looks like this:
The key information: a table element with id idAttachmentsTable contains a tbody element, that has tr elements including td elements with class ms-vb. If the file is already attached to the item, then the file name is included in a child a element. If the file has been just uploaded, a span element includes the full path and the file name.
The next task is to find out how we can get the name of the file we would like to attach.
Analyzing the HTML of the page we can found an input element of type file under the td element with id attachmentsOnClient:
So first I tried to use the value of the onetidIOFile input field, but it turned out that the value of this field does not change as we attach further files to the item.
Assuming we upload the files file1.docx, file2.xlsx and file3.png in this sequence, the value of the $("#attachmentsOnClient").html() expression changes as described below:
Step 1. attaching file1.docx:
<SPAN dir=ltr><INPUT name=fileupload0 title="Name " class=ms-fileinput id=onetidIOFile type=file size=56 value=C:\directory\file1.docx></INPUT> </SPAN>
Step 2. attaching file2.xlsx:
<SPAN dir=ltr><INPUT name=fileupload0 title="Name " class=ms-fileinput id=onetidIOFile style="DISPLAY: none" type=file size=56 value=C:\directory\file1.docx></INPUT> </SPAN><INPUT name=fileupload1 tabIndex=1 title=Name class=ms-longfileinput id=fileupload1 type=file size=56 value=C:\directory\file2.xlsx>
Step 3. attaching file3.png:
<SPAN dir=ltr><INPUT name=fileupload0 title="Name " class=ms-fileinput id=onetidIOFile style="DISPLAY: none" type=file size=56 value=C:\directory\file1.docx></INPUT> </SPAN><INPUT name=fileupload1 class=ms-longfileinput style="DISPLAY: none" type=file value=C:\directory\file2.xlsx><INPUT name=fileupload2 tabIndex=1 title=Name class=ms-longfileinput id=fileupload2 type=file size=56 value=C:\directory\file3.png>
We can see, that former input fields of type file got hidden via style="DISPLAY: none", and new file input elements are appended to the existing ones, That means, we can get the path of the actually attached file from the last file input element.
Last action is to replace the default event handler method (OkAttach) on the OK button. In the new event handler we get the name of the file being actually appended and compare it with the file names of other attachments (attached either in this editing session or already saved to the item). If we find a file with the same name, then a warning is displayed. If there is no conflicting attachment, then we call the default event handler that registers the file to be uploaded as attachment.
- $(document).ready(attachEventHandlers);
- function attachEventHandlers() {
- // override the default event handler with our custom method
- $('#attachOKbutton').attr("onclick", "onAttachOKbuttonClicked()");
- }
- function onAttachOKbuttonClicked() {
- // get the name of the file last attached to the item
- var newFilePath = $('#attachmentsOnClient').find('input').last().val();
- // get the file name from the file path as described at
- // http://stackoverflow.com/questions/423376/how-to-get-the-file-name-from-a-full-path-using-javascript
- // TrimWhiteSpaces is a js method of SharePoint to filter out special characters from the file name
- var newFileName = TrimWhiteSpaces(newFilePath).replace(/^.*[\\\/]/, '');
- var foundDuplication = false;
- $('#idAttachmentsTable').find('tbody').find('tr').each(function () {
- var existingFileName = $(this).find('.ms-vb').find('a').text();
- // if the existingFileName is empty then the attachment was uploaded in this session
- // that is, it is not saved yet
- if (existingFileName == '') {
- var existingFilePath = $(this).find('.ms-vb').find('span').text();
- existingFileName = existingFilePath.replace(/^.*[\\\/]/, '');
- }
- if (newFileName == existingFileName) {
- foundDuplication = true;
- return false;
- }
- });
- if (foundDuplication) {
- alert("A file with name '" + newFileName + "' is already attached to this item.");
- }
- else {
- // call the OkAttach js method of SharePoint
- // this is the method that is originally called by uploading attachments
- OkAttach();
- }
- }
Hopefully you can apply this method to make the user experience better (or at least less frustrating) when working with attachments.
