question

CharlesGraham-0062 avatar image
0 Votes"
CharlesGraham-0062 asked TongZhangMSFT-7548 edited

Getting a SharePoint list and attachments at the same time using javascript

Brief synopsis of what i am trying to do:
I have a list with the following fields: document type, title of the entry, and an attachments field.

I need to get the entries along with the url(s) to the attachment(s) for the list item. I have it mostly figured out, but i can't seen to get the process to wait until i have all the information before sending it to the browser page. I know how to get the things separately, but do not know how to - or if it's even possible - to get the list item and attachment info at the same time - rather than doing two separate async queries.
I would like to get the list items, group them by document type and display separate groupings on the page that open an attachment modal when you click the item's displayed title. When i try to do this, it always paints the items before the attachments are actually added to the JSON object data.

here is the code i have

     var fileList = [];
 var finished = false;
 function loadBootstrap() {
     //check for the required boostrap stuff
     var bootJs = document.querySelector('head').querySelector('#bootstrap-js');
     if (!bootJs) {
         bootJs = document.createElement('script');
         bootJs.setAttribute("src", "https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js");
         bootJs.id = "bootstrap-js";
         document.querySelector('head').append(bootJs);
     }

     var popper = document.querySelector('head').querySelector('#popper');
     if (!popper) {
         popper = document.createElement('script');
         popper.setAttribute("src", "https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js");
         popper.id = "popper";
         document.querySelector('head').append(popper);
     }
 }
 function getList() {
     try {
         if (typeof $().jquery === 'unefined') {
             let jqueryJs = document.createElement('script');
             jqueryJs.setAttribute("src", "/netcom/sites/516SB/SiteAssets/JScripts/jquery-3.3.1.min.js");
             jqueryJs.id = "jquery-js";
             document.querySelector('head').append(jqueryJs);
             let jqueryWaiter = setInterval(() => {
                 if (typeof $().jquery !== 'unefined') {
                     clearInterval(jqueryWaiter);
                     jqueryWaiter = null;
                     loadBootstrap();
                 }
             });
         } else {
             loadBootstrap()
         }
     } catch {
         let jqueryJs = document.createElement('script');
         jqueryJs.setAttribute("src", "/netcom/sites/516SB/SiteAssets/JScripts/jquery-3.3.1.min.js");
         jqueryJs.id = "jquery-js";
         document.querySelector('head').append(jqueryJs);
         let jqueryWaiter = setInterval(() => {
             if (typeof $ !== "undefined" && typeof $().jquery !== 'unefined') {
                 clearInterval(jqueryWaiter);
                 jqueryWaiter = null;
                 loadBootstrap();
             }
         });
     }


     getListItems('Staff Docs List',
         function (listItems) {
            
             for (var i = 0; i < listItems.length; i++) {
                 GetAttachments(listItems[i],
                     function (sendera, args) {
                         console.log(args.get_message());
                     });
                 fileList.push(listItems[i]);
             }
             let finishedWaiter = setInterval(() => {
                 let totalFilesWithAttachments = fileList.map(x => x.hasAttachments).length;
                 let totalAttachmentsFinished = fileList.map(x => x.attachements!==undefined).length;
                 if (totalAttachmentsFinished == totalFilesWithAttachments) {
                     clearInterval(finishedWaiter);
                     finished = true;
                     buildIt();
                 }
             });
         },
         function (sendera, args) {
             console.log(args.get_message());
         });
 }

 class AttachmentWindow {
     constructor(attachementList, itemName) {
         this.html = this.build();
     }
     build() {
         let html = document.createElement('div');
         html.className = "modal fade";
         html.id = "myModal";
         html.innerHTML = `<div class="modal-dialog">
         <div class="modal-content">
             <div class="modal-header"> Documents for <span class="item-name"></span>
                 <button class="close btn bnt-danger" aria-label="close modal" data-dismiss="modal">✕</button>
             </div>
             <div class="modal-body">
             </div>
         </div>`
         return html;
     }
 }
 class StaffDocs {
     constructor(item) {
         this.title = item.title;
         this.attachments = item.attachments;
         return this.build();
     }
     build() {
         let html = document.createElement('div');
         html.className = "document-item";
         html.innerText = this.title;
         html.title = "click to see attachments";
         html.dataset.toggle = "modal";
         html.dataset.target = "#myModal";
         html.addEventListener('click', () => {
             let modal = document.querySelector('.modal');
             let title = modal.querySelector('.item-name');
             title.innerText = this.title;
             let content = modal.querySelector('.modal-body');
             content.innerHTML = '';
             this.attachements.forEach(item => {
                 let attachmentDiv = document.createElement('div');
                 attachmentDiv.innerHTML = `<div><a href="${item.url}" target="_blank">${item.name}</a></div>`;
                 content.append(attachmentDiv);
             });

         });
         return html;
     }
 }

 class DocCategory {
     constructor(typeName, files) {
         this.typeName = typeName;
         this.items = files;
         this.css();
         return this.build();
     }
     build() {
         let div = document.createElement('div');
         div.className = this.typeName.replace(' ', '');
         div.className += " flex flex-box";
         div.innerHTML = `<h2>${this.typeName}</h2><hr />`;
         let fileContents = document.createElement('div');
         div.append(fileContents);
         fileContents.className = "fileList";
         this.items.forEach(item => {
                 let doc = new StaffDocs(item);
                 fileContents.append(doc);           
         });
         return div;
     }
     css() {
         var style = document.querySelector('head').querySelector('#staffDocsCss');
         if (!style) {
             style = document.createElement('style');
             document.querySelector('head').append(style)
             style.id = "staffDocsCss";
             style.type = "text/css";
             let cssText = `.${this.typeName.replace(' ', '')}{display:flex; width:100%;flex-overflow:wrap;margin-bottom:50px;}
         .${this.typeName.replace(' ', '')} .document-item{flex - basis:row;width:100%}`;
             style.append(document.createTextNode(cssText));
         }
     }
 }
 function buildIt() {
     var waiter = setInterval(() => {
         if (finished) {
             clearInterval(waiter);
             let modal = new AttachmentWindow().html;
             document.querySelector('body').append(modal);
             let docTypes = fileList.map(x => x.documentCategory);
             let target = document.querySelector('.staff-doc-area');
             target.innerHTML = '';
             docTypes.forEach(doc => {
                 let files = fileList.filter(x => x.documentCategory == doc);
                 let category = new DocCategory(doc, files);              
                 target.append(category);
             });
         }
     }, 10)
 }

 function getListItems(listTitle, success, error) {
     let ctx = SP.ClientContext.get_current();
     let list = ctx.get_web().get_lists().getByTitle(listTitle);
     let qry = new SP.CamlQuery();
     let listItems = list.getItems(qry);
     ctx.load(listItems);
     ctx.executeQueryAsync(
         function () {
             let listItemEnumerator = listItems.getEnumerator();
             let attachmentsList = [];
             while (listItemEnumerator.moveNext()) {
                 let item = listItemEnumerator.get_current();
                 Item = item;
                 let title = item.get_item('Title');
                 let documentCategory = item.get_item('Document_x0020_Type');
                 let hasAttachments = item.get_fieldValues()['Attachments'];
                 attachmentsList.push({
                     title: title,
                     documentCategory: documentCategory,
                     hasAttachments: hasAttachments,
                     fileDirRef: item.get_fieldValues()['FileDirRef'],
                     Id: item.get_fieldValues()['ID'],
                     shown: item.get_fieldValues()["Shown_x0020_on_x0020_List"]
                 });
             }
             success(attachmentsList);
         },
         error);
 }
 function GetAttachments(listItem, error) {
     if (listItem.hasAttachments) {
         let ctx = SP.ClientContext.get_current();
         let attachmentFolderUrl = String.format('{0}/Attachments/{1}', listItem.fileDirRef, listItem.Id);
         let folder = ctx.get_web().getFolderByServerRelativeUrl(attachmentFolderUrl);
         let files = folder.get_files();
         ctx.load(files);
         ctx.executeQueryAsync(
             function () {
                 let attachments = [];
                 for (let i = 0; file = files.get_item(i); i++) {
                     attachments.push({ url: file.get_serverRelativeUrl(), name: file.get_name() });
                 }
                 listItem["attachments"] = attachments;
             },
             error);
     }
 }

 SP.SOD.executeFunc('sp.js', 'SP.ClientContext', getList);
sharepoint-dev
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @CharlesGraham-0062,

I am currently doing some research on this issue, will let you know as soon as possible.

0 Votes 0 ·

1 Answer

TongZhangMSFT-7548 avatar image
0 Votes"
TongZhangMSFT-7548 answered TongZhangMSFT-7548 edited

Hi @CharlesGraham-0062,

Thanks for the detailed description of the case. When I received the case, I searched a lot of documents did a lot of researches. And I feel regretful to inform you that according to my research, there is no way to get a SharePoint list and attachments at the same time. It is only possible to get this information separately. Thanks for your understanding and support.


If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.




5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.