1

SP Community, I am absolutely stumped and desperate for help. I have been up and down StackExchange trying to get 3 separate attempts to - 1. query all of the lists within a subsite and to then - 2. filter the query based on criteria in the title.

I need to retrieve all items within each list in a subsite. Once I do that, I need to filter by list title so that only information from lists containing "RDTEN" or "procurement" in their title get parsed. With the end result, I need to build a graph for the aggregated information.

Please see attempts below, these are my starting points, none of which are currently working:

AJAX Test with Multiple Lists - Ajax

<script type="text/javascript">
var siteUrl = 'https://site/subsite';

// Load the required SharePoint libraries.
$(document).ready(function () {

    // The js files are in a URL in the form:
    // web_url/_layouts/15/resource_file
    var scriptbase =  siteUrl  + "/_layouts/15/";

    // Load the js files and continue to
    // the execOperation function.
    $.getScript(scriptbase + "SP.Runtime.js",
    function () {
        $.getScript(scriptbase + "SP.js", execOperation);
        }
    );
});

// Function to execute basic operations.
function execOperation() {

    // Continue your program flow here.
    retrieveWebSiteProperties(siteUrl);

}

function retrieveWebSiteProperties(siteUrl) {
    var clientContext = new SP.ClientContext(siteUrl);
    this.oWebsite = clientContext.get_web();
    this.collList = oWebsite.get_lists();
    this.listInfoCollection = clientContext.load(collList);

    clientContext.executeQueryAsync(
        Function.createDelegate(this, this.onQuerySucceeded), 
        Function.createDelegate(this, this.onQueryFailed)
    );
}

function onQuerySucceeded(sender, args) {

    var listInfo = '';
    var listEnumerator = this.collList.getEnumerator();
    while (listEnumerator.moveNext()) {
        var oList = listEnumerator.get_current();
        listInfo += 'Title: ' + oList.get_title() + ' Created: ' + 
oList.get_created().toString() + '\n';
    }
    $("#chartArea").html(listInfo);

}

function onQueryFailed(sender, args) {
    alert('Request failed. ' + args.get_message() + 
        '\n' + args.get_stackTrace());
}
</script>

<body>
<div id="chartArea"></div>
</body>

CSOM

<script type="text/javascript">
var context;
var web;
var collList;
$(document).ready(function () {
    SP.SOD.executeFunc('sp.js', 'SP.ClientContext', getLists);
});

function getLists() {
    context = new SP.ClientContext.get_current();
    web = context.get_web();
    collList = web.get_lists();
    context.load(collList);
    context.executeQueryAsync(onRequestSuccess, onRequestFailure);
}
function onRequestSuccess() {
    var listInfo = '';
    var listEnumerator = collList.getEnumerator();
    while (listEnumerator.moveNext()) {
        var oList = listEnumerator.get_current();
        if(oList.get_title().indexOf("pro") !== -1){ //if title contains "pro"
            listInfo += '<div>Title: ' + oList.get_title() + ' Created: ' + 
oList.get_created().toString() + '</div>';
        }
    }

    $("#chartArea").html(listInfo);
}
function onRequestFailure(sender, args) {
    $("#chartArea").html('Request failed. ' + args.get_message() + '\n' + 
args.get_stackTrace());
}
</script>

<body>
<div id="chartArea"></div>
</body>

REST

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>Test with Multiple Lists - Rest</title>
</head>

<script type="text/javascript">
// Set the REST endpoint to use. 
// This one includes a filter to only return lists whose title includes "Site"
var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists? 
$filter=substringof('Site', 
Title)";

// Create the AJAX request using jQuery. 
var request = jQuery.ajax({ url: url, headers: { "Accept": 
"Application/json;odata=nometadata" } });

   // Use a .then() callback to do something with data after its returned by the server
 request.then(
     function (d) {
      // For each result in the set of returned data
      d.value.forEach(
          function (i) {
              // Print the Title of the list to the console
              console.log(i.Title);
          });
  });

 </script>

<body>
<div id="chartArea"></div>
</body>

Note: My original question was put on hold for being unclear, I wrote a new question in hopes to provide additional clarity.

  • I refactored my code a bit... Might be easier to read now? Apologies. – KGlasier Jan 4 at 21:12
1

I've got a script here that'll do most of what you're looking for. Currently it doesn't create a graph or any fancy stuff but it does collect the info you're looking for. Be careful that your internal column name actually is Title or you'll have to change it in the for loops in getSPListData_SecondQuery_Success.

The only things you'll really need to change is the variables siteUrl, and potentially expr. The data from each list is sent to the manageData function under allData whereas the items that meet your criteria will be sent to oListData.

siteUrl must be the absolute url of the site, without including the page. For example: http://mySites/sample/infrastructure rather than http://mySites/sample/infrastructure/home.aspx.

expr is a regex expression. In this case it's saying find any instance of "RDTEN" or "procurement", case insensitive. If you need help with regex expressions, there's lots of guides you can find with a quick google search. In JS they are notated by /<pattern>/<flags>.

In manageData you can use console.log(allData) or console.log(oListData) to see what's in the respective items.

The general flow has been split into functions as I find it easier to read that way... Here's an outline:

Load JavaScript libraries with an anonymous function.

Wait for SP.js to load for SP.ClientContext to be loaded, then call getSPListData

getSPListData :: Prepare and execute the first query to gather all the lists.

If successful, send current context to getSPListData_SecondQuery and prepare second query

If failed, log the issue through getSPListData_LogError.

getSPListData_SecondQuery :: Prepare and execute second query to gather all items in lists.

If successful, send current context to getSPListData_SecondQuery_Success to process the list items.

If failed, log the issue through getSPListData_LogError.

getSPListData_SecondQuery_Success :: Process items by looking at the title of every list item. If matches, push into a list.... Once complete, push the valid list data (oListData) and all item (result, or allData in the next function) to manageData.

manageData :: Used to manipulate the list items in the array. Can use console.log(oListItems) or console.log(allData) to view whats in the respective arrays in the console. Currently puts the first 5 into a list wherever your Code Editor is on the page.

This isn't the most efficient evaluation as it does the two queries which can take time, and then at the end it has a rather large run-time complexity from the nested for loops. If you've got a lot of lists or items, you may need to optimize some of it.

Just paste and edit this into a Script Editor on whatever page you want. Right now it creates a div to send the data to in the form of...

Title = itemTitle
Library = relativeUrl
Blank Line

Heres the script:

Files: <br/><div id="listItemData"></div><br/>

<script type="text/javascript">
// Loads libraries from CDNs... 
javascript: ( function() {
    function l( u, i ) {
        var d = document;
        if ( !d.getElementById( i ) ) {
            var s = d.createElement( 'script' );
            s.src = u;
            s.id = i;
            s.async = true;
            d.body.appendChild( s );
        }
    }
    // l( url, idForElem )
    l( '//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js', 'msAjax' )
    l( '//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js', 'jQuery' )
} )();

// Wait for SP.js to finish loading before we run the queries.
SP.SOD.executeOrDelayUntilScriptLoaded( getSPListData, 'SP.js' );

function getSPListData() {
    // Set up the first query
    this.result = [];
    this.siteUrl = 'http(s)://mySite/sample/subSite'; // Change this to your subsite in question.
    this.ctx = new SP.ClientContext( siteUrl )
    this.lists = ctx.get_web().get_lists();
    this.expr = /(RDTEN)|(procurement)/i // This is what you're searching for in the Title field, "i" for case insensitive search.
    this.ctx.load( this.lists, "Include(Id,Title)" );

    ctx.executeQueryAsync( 
      this.getSPListData_SecondQuery.bind(this), 
      this.getSPListData_LogError.bind(this) 
    );

}

function getSPListData_SecondQuery(sender, args){
   lists.get_data().forEach( function( list ) {
      // Set up the second query and push its results into the "Result" array
      var items = list.getItems( SP.CamlQuery.createAllItemsQuery() );
      ctx.load( items );
      // This entry is the list's base data
      var listEntry = {
           id: list.get_id().toString(),
           title: list.get_title()
      }
      // Push the data into result, items will have all items in each list.
      result.push( {
           list: listEntry,
           items: items
      } );
   } );
   ctx.executeQueryAsync(
      this.getSPListData_SecondQuery_Success.bind(this),
      this.getSPListData_LogError.bind(this)
   );
}

function getSPListData_SecondQuery_Success(sender, args){
   //transform listitem properties. This is where the "items" section of "Result" is filled out.
   result.forEach( function( item ) {
       item.items = item.items.get_data().map( function( listItem ) {
          return listItem.get_fieldValues();
       } );
   } );

   // Filter each by the ReGex expression earlier on the Title field.
   var oListData = [];
   var itemTitle;
   for ( listNum = 0, listTot = result.length; listNum < listTot; listNum++ ) {
       for ( itemNum = 0, itemTot = result[ listNum ].items.length; itemNum < itemTot; itemNum++ ) {
          itemTitle = result[ listNum ].items[ itemNum ].Title
          if ( itemTitle && itemTitle.match( expr ) ) {
               // put data into a list
               oListData.push( result[ listNum ].items[ itemNum ] )
          }
       }
   }
   // Here's where you can make the data visible. in the manageData function.
   manageData( oListData, result );
}

// incase an error comes up in the execution of the queries
function getSPListData_LogError( sender, args ) {
    console.log( args.get_message() ); 
}

function manageData( oListData, allData ) {
    // Do stuff with list items here...
    var oListDataField = document.getElementById( "listItemData" );
    var stringBuilding = '';

    for(i=0, itemMax = Math.min(5, oListData.length); i < itemMax; i++){
        stringBuilding += " Title = " + oListData[i].Title + "<br/>"
        stringBuilding += " Library = " + oListData[i].FileDirRef + "<br/><br/>"
    }
    oListDataField.innerHTML = stringBuilding

    // For seeing the relative data:
    console.log(allData)
    console.log(oListData)
}

</script>
  • thanks so much for this KGlasier, testing it out this morning – Torybee Jan 7 at 14:04
  • okay @Torybee and if the site you want the list items from is the same as the site you want to display it, you should be able to replace this.ctx = new SP.ClientContext(site); for this.ctx = new SP.ClientContext.get_current();... That should make it useable on any site without alteration if you want the same title search – KGlasier Jan 7 at 15:33
  • great to know, this is working for me! A little slow like you said but I can work on that. I really appreciate your help, thanks so much – Torybee Jan 7 at 15:40
  • @Torybee I got the skeleton of this code from this answer but it links to a possible method to do all this in a single request which you may want to look into for speed (Request Batching - CSOM). Also using a better query would improve response time as you may be able to search for your RegEx items in the query itself, removing that double for loop. And an upvote is always appreciated ;) – KGlasier Jan 7 at 15:46
  • I'll definitely keep that in mind, I tried to upvote you but my account is too young apparently haha I have less than 15 reputation :( – Torybee Jan 7 at 17:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.