2010, 2013, 2016, Development Blog, jQuery, Office 365, SharePoint
Clean CSOM JavaScript structure to access SharePoint list data
The code examples below work on SharePoint 2010, 2013 and 2016.
The problem:
You want to create clean, maintainable CSOM for SharePoint and ensure that you:
- don’t override any SharePoint default variables
- don’t override any third party JavaScript frameworks that are running on your site
The answer:
Encapsulate your entire JavaScript library in a variable, which will handle all your functions and global variables. This is the structure I follow routinely, and with even the most complicated JavaScript calls, this is still very maintainable.
I hope the code samples below help you. Please also look at SharePoint JavaScript CSOM – currentItem.get_item(columnName) – how do I get at the property options and values? to see all the out-of-box options for listItem.get_items(KEY).
The basic structure:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var yourUniqueVar = { "g": { }, "init": function() { // Load additional JS libraries required to execute your code }, "mainFunction": function() { // All JS libraries and other inits are now loaded // Prep data objects, and toss them at the client context }, "success": function(sender, args) { // Iterate through data, create data object and add it to your globals }, "fail": function(sender, args) { // Handle errors }, "renderHTML": function() { // Use data object created in "success" to render HTML }, "finalise": function() { // Wrap up anything else that needs to happen } } |
A code example:
This is the JavaScript necessary for pulling the data. (FYI – this relies on jQuery, so load it via CDN if necessary).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | var stephy = { /* Define global variables here */ "g": { /* Relative Site URL */ "siteUrl": "/sites/MySiteName", /* Library Display Name - we'll use the Pages library for this example */ "libraryName": "Pages", /* Library object to house data */ "library": null, /* Array to house list item objects */ "items": [], /* Web object to put the web's information into */ "web": null }, /* Init function */ "init": function() { // Add a loader (to give your users a pacifier) $('#stephyDiv').addClass("stephy-loading"); // Load necessary libraries SP.SOD.executeFunc('sp.js', 'SP.ClientContext', stephy.loadData); }, /* Prep the list loading function */ "loadData": function() { // Create all items CAML query (gets all items in a list) var camlQuery = new SP.CamlQuery.createAllItemsQuery(); // Point CAML at the library camlQuery.set_folderServerRelativeUrl(stephy.g.libraryName); // Get the clientContext, which will handle the request with the current user's permissions var clientContext = new SP.ClientContext(stephy.g.siteUrl); // Get the web object stephy.g.web = clientContext.get_web(); // This puts the web object in the clientConext (to get the data) and is also globally available so you can call it later clientContext.load(stephy.g.web); // Set a local variable to handle the library request var library = stephy.g.web.get_lists().getByTitle(stephy.g.libraryName); // Now add it to a global for access in the success object stephy.g.library = library.getItems(camlQuery); // This puts the library in the clientConext (to get the data) and is globally available so you can call it later clientContext.load(stephy.g.library); /* You can repeat this process and throw multiple list requests at the same clientContext so * it is executed in one AJAX request - just use different library objects (so each list is accessible in your success function) * CAUTION - if you do throw multiple lists / objects into the same clientContext request, one of them failing results in the entire request failing */ // Execute Query - this throws it at SharePoint, and once complete, will run your getAndPopulateDataSuccess function, or fail if there's a problem clientContext.executeQueryAsync( Function.createDelegate(this, stephy.getAndPopulateDataSuccess), Function.createDelegate(this, stephy.onQueryFailed) ); }, /* After clientContext handles AJAX request, this runs on success */ "getAndPopulateDataSuccess": function(sender, args) { // Get site information from the (now populated) global variable stephy.g.web var message = "\n Title: " + stephy.g.web.get_title(); message += "ID: " + stephy.g.web.get_id() + "</br>"; message += "Language: " + stephy.g.web.get_language() + "</br>"; message += "UI Version: " + stephy.g.web.get_uiVersion() + "</br>"; message += "Description: " + stephy.g.web.get_description() + "</br>"; message += "Created: " + stephy.g.web.get_created(); // Put it on the page so you can view it $('#stephyWebDiv').html(message); // Get library data from the (now populated) global variable stephy.g.library var listItemEnumerator = stephy.g.library.getEnumerator(); while (listItemEnumerator.moveNext()) { // Get the current list item var listItem = listItemEnumerator.get_current(); // Now load whatever other data you want to load, ie: var title = listItem.get_item('Title'); var url = listItem.get_item("FileRef"); /* I prefer to push all the objects into an array first and then iterate * over the data in the next function to create clear separation between data and layout */ stephy.g.items.push({ "title": title, "url": url }); } stephy.renderHTML(); }, /* After clientContext handles AJAX request, this runs on failure with an error message */ "onQueryFailed": function(sender, args) { alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); }, "renderHTML": function() { // Loop through the data and populate the HTML variable var html = ""; $.each(stephy.g.items, function(index, value) { html += '<div>'; html += '<div>' + value.title + '</div>'; html += '<div>' + value.url + '</div>'; html += '</div>'; }); // Remove the loader $('#stephyDiv').removeClass('stephy-loading'); // Add the HTML to your container $('#stephyDiv').html(html); // Run any additional init functions here (ie. if you’re relying on another framework to create a carousel or something) } } // On page load, run the init function $(document).ready(function() { stephy.init(); }); |
And here is the HTML (and some basic styling) necessary to make this work.
1 2 3 4 5 6 7 | <div id="stephyDiv" class="stephy-loading">No list information yet.</div> <div id="stephyWebDiv" class="stephy-loading">No web information yet.</div> <style> .stephy-loading { background-color: red; } </style> |
About Author
Comments are closed