Home > development, Sharepoint > Using jQuery Queue with SPServices

Using jQuery Queue with SPServices

November 20th, 2013

One of the problems I came across the other day is I had several hundred items in a list to process.  To make life easy I use javascript on a web part page to make an app to process the items I wanted to do. 

However when its hundreds, do them all at once and you’re in trouble.  You block the UI thread, you cant update any status values, I dare not think what would happen if you called a couple of hundred async ajax queries all at once, it might just handle them – you can try it if you want ;-)

To get round this I thought I’d try to use jQuery queues.  So in this example I have a custom list which I get data from, I’m using promises to get the data but there was no need, I just used some code from the last example.  Once I have the data I inject it onto the screen an lose the original data array (now this is the point where I should use knockout and let the screen adjust to the observed data, but this is a demo).  Then on a click event, a big process this now button, I iterate thru each item on the page, gets its details and add a function to the queue that calls another function (just for being tidy I could embed) which makes a call to SPServices async update, phew.

Then I tell the queue to start executing the functions in it, one at a time.  At the end of each async success, it calls the next function, you might spot the mistake here, what if it doesn’t succeed (well I forgot to code it, but you need to do something with the item and the queue when you do it).

Hint: When calling functions and sub functions, make sure you “var” every variable, I forgot and it only updated the last item.

Technorati Tags: ,,

Here’s the code

 

 <script src="js/jquery.SPServices-0.7.1a.min.js"></script>  <script src="js/underscore.min.js"></script>   <div id="mainApp" > 	<div id="appStatus">Initialising</div>	<div id="appButton" style="cursor:hand;display:none">Click Me</div> 	<div id="appBody"></div>  </div>        <script>


var binaryJamQueueTest = function ($) {
   
   	//Private Members
  	var testListArray;

	function main() {
		
		$("#appStatus").text("Loading");

		//Remember that $.when is an async function also, so dont put anything after this code
		//unless you want it running immediately, in which case stick it here first.
		$.when(asyncGetTestList())
		.fail(function() {
			loadFailure();
		})
		.done(function(){
			dataReady();
		});
		
  	}
  	
  	function loadFailure() {
  		//Oh dear
	  	$("#appStatus").text("Failed to Load data");
  	}
  	
  	function dataReady() {
  		$("#appStatus").text("Processing Data");
  		
  		//Earlier versions did not queue so in cases where you will thread block
  		//use something like this to give the DOM time to update
  		setTimeout(function() {
	  		processList();
	  	}, 10);
  		
  	}
  	
  	
  	function asyncGetTestList() {
  	
  		var dfd = $.Deferred();
  		
		$().SPServices({          
			operation: "GetListItems",          
			async: true,          
			listName: "TestList", 
			CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='name' /><FieldRef Name='valueField' /></ViewFields>",

			completefunc: function(data, status) { 
				if (status== "success") {
					testListArray=$(data.responseXML).SPFilterNode("z:row").map(function() 
	                { 
							return {
								id: $(this).attr('ows_ID'), 
		                        title: $(this).attr('ows_Title') , 
		                        name: $(this).attr('ows_name') ,
		                        value: parseInt($(this).attr('ows_valueField')) 
		                    }; 
	                 }); 
					dfd.resolve("");				
				}
				else
				{
					dfd.reject();
				}
			} 
		}); 
		
		return dfd.promise();
  	}
  	
  	
  	function updateListItem(id, title, value, $item, next)
  	{
		//Notice here, if I was databinding I would only have to update the value not the html item
	  	$().SPServices({
			operation: "UpdateListItems",
			async: true,
			ID: id,
			listName: "TestList",
			valuepairs: [ ["valueField", value]],
			completefunc: function(xData, Status) {
				$item.text(title + " " + value);
				$item.attr('value', value);
				next();
			}
		});
	
  	}
  	
  	function processList()
  	{
		var $taskQueue=$({});
		
  		var htmlAdd="";
		$.each(testListArray, function(locIndex, testListRow) {
			
				htmlAdd+="<li id='" + testListRow.id + 
								"' title='" + testListRow.title + 
								"' name='" + testListRow.name + 
								"' value='" + testListRow.value + 
						  "'>" + testListRow.title + " " +
						 testListRow.value + 
						 "</li>";
								
				s="";
			
		});
		
		//Clear the original list Im going to use stuff onscreen, I know its wrong and not MVC
		//But Hey you do it the right way with a data binding library instead
		testListArray={};
  		
  		html=$("<ul id='itemsToProcess'>" + htmlAdd+ "</ul>");
		$("#appBody").html(html);
  		$("#appStatus").text("Ready");
  		$("#appButton").show();



  		$("#appButton").click(function() {
  		
			$.each($("#itemsToProcess").children(), function() {
				var $currentLi=$(this);
				$taskQueue.queue('tasks', function(next) {
	  				var id =$currentLi.attr('id');
	  				var title =$currentLi.attr('title');
	  				var value=parseInt($currentLi.attr('value'));
	  				updateListItem(id, title, value+1, $currentLi, next );
	  				
	  				
				});
			});

			$taskQueue.dequeue('tasks');
  		});
  				
  	}


	//Public Members
  	return {
   		init : main
  	}

  
}(jQuery); //binaryJamQueueTest Module


jQuery(function () {

    binaryJamQueueTest.init();
});


</script>  
Categories: development, Sharepoint Tags:
  1. November 20th, 2013 at 16:27 | #1

    I’m curious. Did you consider batching your updates rather than doing them one at a time using the default UpdateListItems batch approach? It would reduce your calls (you might get away with 100 updates in one batch).

    M.

  2. November 20th, 2013 at 17:10 | #2

    Of course Marc makes a great point. Doing it one at a time is stupid. This was an example of using queues. You could combine this with batching for very large updates.

  3. November 20th, 2013 at 17:23 | #3

    Not stupid. ;+) I was just wondering if batching made sense based on what you were trying to do.

    The queuing bit is something I want to take a look at now. It could probably help with the processing efficiency where there are multiple calls to SPCascadeDropdowns, for instance. I’ve been using .data() to store the “queue” of children per parent, but it would probably be better if I could queue the functions.

    M.

Comments are closed.