Tuesday, December 12, 2017

SharePoint JSOM CAML Query

Here is some sample SharePoint JSOM code to query a library for items with a specific content id and assigned to a specific user. This code also recurses folders, returns extra fields and orders the results.

Note: The getCurrentUser function would have to be another JSOM asynchronous call and wouldn't work exactly the way I have it here. It would have to execute first, then call queryItems from it's success callback.

JavaScript code

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <script type='text/javascript'>
        /**
        * Executed by jQuery after the DOM has loaded, loads the SharePoint JSOM client
        * library
        * @name Ready
        * @param none
        * @returns null
        */
        $().ready(function () {

            // Load the SharePoint JSOM library, then continueReady
            SP.SOD.executeFunc('sp.js', 'SP.ClientContext', continueReady);

        }); // end ready

        /**
        * Called by jQuery ready after loading the SharePoint JSOM client library
        * @name continueReady
        * @param none
        * @returns null
        */
        function continueReady() {

            // Set the contenttype id prefix to "Document Sets"
            var contentTypeIdPrefix = '0x0120D520';

            // Do other ready actions

            // Get the currentUser*
            var currentUser = getCurrentUser();

            // Query for items
            queryItems(contentTypeIdPrefix, currentUser);

            /** IMPORTANT: You cannot do anything here!
            *   queryItems will issue an asynchronous call
            *   and any code placed here will not get executed
            */

        }; // end continueReady

        /**
        * Queries for list items with the passed contenttypeid prefix and assigned to the passed user
        * @name queryItems
        * @param {string} CtId - The contenttypeid prefix of the items to query
        * @param {object SPUser} passedUser - The user to use for Assigned To
        * @returns null
        */
        function queryItems(CtId, passedUser) {

            // Get the current context and rootweb
            var ctx = new SP.ClientContext.get_current();
            var oWeb = ctx.get_site().get_rootWeb();

            // Get the list or library to query
            this.oList = oWeb.get_lists().getByTitle('Cases');

            /** Build our CAML Query to get all items with the passed content id prefix
            *   and assigned to the passed user. I purposedly made this query somewhat
            *   complex to illustrate recursing folders, sorting, and multiple complex
            *   where conditions on non-text fields
            *   TIP: I like to build my queries like this so I can more easily see that
            *   they are correctly formed. Because, if they are not, you will not get any
            *   results to your query or any clue as to why it failed. Once the Caml is
            *   tested and proven, you could build it more efficiently if you desire.
            */
            var caml = "";
            caml += "<View Scope='RecursiveAll'>";
            caml += "  <Query>";
            caml += "    <OrderBy>";
            caml += "      <FieldRed Name='Title' Ascending='True' />";
            caml += "    </OrderBy>";
            caml += "    <Where>";
            caml += "      <And>";
            caml += "        <BeginsWith>";
            caml += "          <FieldRef Name='ContentTypeId' />";
            caml += "          <Value Type='ContentTypeId'>" + CtId + "</Value>";
            caml += "        </BeginsWith>";
            caml += "        <Eq>";
            caml += "          <FieldRef Name='AssignedTo' LookupId='TRUE' />";
            caml += "          <Value Type='User'>" + currentUser.get_id() + "</Value>";
            caml += "        </Eq>";
            caml += "      </And>";
            caml += "    </Where>";
            caml += "  </Query>";
            caml += "</View>";

            // Instantiate the query
            var query = new SP.CamlQuery();
            query.set_viewXml(caml);
            this.listItems = oList.getItems(query);

            // Load, and request viewfields (use field internalnames)
            ctx.load(listItems, 'Include(Title, CaseName, EncodedAbsUrl)');

            // Execute asynchronous
            ctx.executeQueryAsync(
                Function.createdDelegate(this, queryItems_Success),
                Function.createDelegate(this, queryItems_Failure)
            );

        }; // end queryItems

        /**
        * On queryItems success, use the results from the query
        * @name queryItems_Success
        * @param {object} sender - system object
        * @param {args} sender - system object
        * @returns {null}
        */
        function queryItems_Success(sender, args) {

            // Enumerate the list items returned from the query
            var itemEnum = this.listitems.getEnumerator();

            // Loop through the the returned listitems
            while (itemEnum.moveNext()) {

                // Get the item
                var currentItem = itemEnum.get_current();

                // Now we have access to the fields we queried for
                var itemID = currentItem.get_item('ID');
                var itemTitle = currentItem.get_item('Title');
                var itemCaseName = currentItem.get_item('CaseName');
                var itemCaseUrl = currentItem.get_item('EncodedAbsUrl');
               
                // Do whatever with the data...
            }

        }; // end queryItems_Success

        /**
        * On queryItems failure, handle the error
        * @name queryItems_Failure
        * @param {object} sender - system object
        * @param {args} sender - system object
        * @returns {null}
        */
        function queryItems_Failure(sender, args) {

            // Do something with the error message
            alert('ERROR, Failure queryItems: ' + args.get_message());
            console.log('ERROR, Failure queryItems: ' + args.get_message());

        }; //end queryItems_Failure
    </script>

</body>
</html>


Friday, December 8, 2017

JavaScript Arrays, Hash Tables, and Objects

I’ve been writing a lot of JavaScript lately for SharePoint and when I need to store or manipulate lists of data I cannot remember the JavaScript rules and best practices for using arrays, hash tables, and objects. This post is to remind me of the techniques I’ve learned through research and trial and error.

Hint: You can cut and paste this code into JavaScript try it editor, like http://editor.javascriptkit.com/, and experiment.

JavaScript code

<script type='text/javascript'>

// Instantiate an array
var myArray = [];

// Instantiate a hash table
var myHash = [];

// Instantiate an object hash
var myObjects = []

// If you re-use any of these and need to clear, use the following
myArray.length = 0;
myHash.length = 0;
Object.keys(myObjects).length = 0;

// Add array elements
myArray.push('Dodge');
myArray.push('Audi');
myArray.push('Ford');

// Add hash entries
myHash['Dodge'] = 'RAM 1500';
myHash['Audi'] = 'S4';
myHash['Ford'] = 'Escape';

// Add has object entries
myObjects['Dodge'] = { model: 'RAM 1500', color: 'Blue' };
myObjects['Audi'] = { model: 'S4', color: 'Silver' };
myObjects['Ford'] = { model: 'Escape', color: 'Red' };

// Remove entries
myArray.splice(myArray.indexOf('Audi'), 1);
delete myHash['Audi'];
delete myObjects['Audi'];

// Determine if contains key
document.write('<b>Contains key...</b><br>')
if (myArray.indexOf('Dodge') >= 0) {
    document.write('- found "Dodge" in myArray!<br>');
}
if (myHash['Dodge'] != undefined) {
    document.write('- found "Dodge" in myHash!<br>');
}
if (Object.keys(myObjects).indexOf('Dodge') >= 0) {
    document.write('- found "Dodge" in myObjects!<br>');
}

// Iterate an array
document.write('<br><b>myArray iteration...</b><br>')
for (var i = 0; i < myArray.length; i++) {
    document.write('- myArray: ' + myArray[i] + '<br>')
}

// Iterate a hash
document.write('<br><b>myHash iteration...</b><br>')
for (var key in myHash) {
    document.write('- key/value: ');
    document.write(key + '/');
    document.write(myHash[key] + '<br>');
}

// Iterate a hash of objects
document.write('<br><b>myObjects iteration...</b><br>')
for (var key in myObjects) {
    document.write('- key/model/color: ');
    document.write(key + '/');
    document.write(myObjects[key].model + '/');
    document.write(myObjects[key].color + '<br>');
}

</script>

Output