Using jQuery Queue with SPServices

November 20th, 2013 3 comments

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:

Using jQuery promises with SPServices

November 18th, 2013 2 comments

I had reason to pull in data from three separate lists in SharePoint recently. Data in list three was dependant on lists one and two.

So I created an admin app page to manage problems with list three.  Having to pull data from all three lists, left me with some options

  • load them synchronously
  • nest the calls in successive succeeded function
  • Use jQuery promises

Perhaps someone has done this and there is a good example out there, but I couldn’t find it so I figured this out for me and am posting it because, well you can’t have enough examples.

This code is just enough of the original to demonstrate promises, I tested the original but had to change some details here which of course I havent had time to check, so I hope this works (it should with the lists in place) and give you enough insight.

In this code look at the $.when statement, the way I’m using it means that it will execute each function in turn and only continue if all functions suceed, if one fails it will execute the loadfailure function instead.

EDIT:As Marc comments below, SPServices returns a promise now so no need to build your own, see Marcs link
for more details. This code is still handy for seeing how to use promises with an async call, but this is not how to do it any more. This is quite messy code too.  When you start to use more structured code, SPA frameworks, then this method doesn’t really fit and the returned promise fits better with service or provider patterns unlike this jumble pattern here ;-).

 
<script language="javascript" type="text/javascript" src="js/jquery-1.7.min.js"></script>  
<script language="javascript" type="text/javascript" src="js/jquery.SPServices-0.7.1a.min.js"></script>  
<script language="javascript" type="text/javascript" src="js/underscore.min.js"></script>   
<div id="mainApp">
 <div id="appStatus">Initialising</div>
 <div id="appBody"></div>
</div>
<script>
var binaryJamPromisesTest = function ($) {
   
   	//Private Members
   
  	var listOne, listTwo, listThree;

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

		$.when(asyncGetListOne(), asyncGetListTwo())
		.fail(function() {
			loadFailure();
		})
		.done(function(){
			dataReady();
		});
  	}
  	
  	function loadFailure() {
	  	$("#appStatus").text("Failed to Load data");
  	}
  	
  	function dataReady() {
  		$("#appStatus").text("Processing Data");
  		
		//processLists();  //Do the main thread work here !
  	}
  	
  	
  	function asyncGetListOne() {
  	
  		var dfd = $.Deferred();
  		
		$().SPServices({          
			operation: "GetListItems",          
			async: true,          
			listName: "ListOne", 
			completefunc: function(data, status) { 
				if (status== "success") {
					_listOne=$(data.responseXML).SPFilterNode("z:row").map(function() 
	              	  		{ 
						return {
							id: $(this).attr('ows_ID'), 
				                        title: $(this).attr('ows_Title') 
	                			    }; 
			                 }); 
					dfd.resolve("");				
				}
				else
				{
					dfd.reject();
				}
			} 
		}); 
		
		return dfd.promise();

                
  	}

  	function asyncGetListTwo() {
  	
  		var dfd = $.Deferred();
  		
		$().SPServices({          
			operation: "GetListItems",          
			async: true,          
			listName: "ListTwo", 
			completefunc: function(data, status) { 
				if (status== "success") {
					_listTwo=$(data.responseXML).SPFilterNode("z:row").map(function() 
	              	  		{ 
						return {
							id: $(this).attr('ows_ID'), 
				                        title: $(this).attr('ows_Title') 
	                			    }; 
			                 }); 
					dfd.resolve("");				
				}
				else
				{
					dfd.reject();
				}
			} 
		}); 
		
		return dfd.promise();
  	}

	//Public Members
  	return {
   		init : main
  	}

}(jQuery); 


jQuery(function () {

    binaryJamPromisesTest.init();
});


</script> 
Categories: Uncategorized Tags:

jQuery mobile – Multi Pages

December 21st, 2012 Comments off

 

We have been playing about with jQuery mobile at the office and its a great way to deliver specific mobile content and of course it works with PhoneGap for compiling those apps to (near native).

But we had a couple of teething issues due to the documentation being a little all over the place and the examples being a little too simple from the recommended approaches, and the voodoo it does.

First Glossary, in jQuery mobile each page is a screen displayed in the browser that is transistioned (sometimes in a fancy way) to or from.  These pages are essentially (ootb) <div> sections with an attribute of data-role="page".  Now in the demos and examples you will find in the docs and other sites these "Multi-Page" demos are seperate pages displayed on the phone, but in terms of files on the file system they are all in the same htm page.

See demo MultiPage-Template

Now this is great for a couple of pages all based on ajax filled content, but where there are many pages then thats the time to split those pages out onto the file system into seperate documents.

The documentation recommends this approach because as the new page is loaded the last page is removed from the DOM thus saving memory (there are techniques to force caching of pages).  This is where the some of the confusion can arise as there are so few examples explaining whats happening.

The default behavior for jQuery mobile when navigating about these separate htm files that are defined as pages of the app is that it uses ajax to load them. It can then take that content and inject it into the DOM and then transition between the two. 

The problem we encountered due to the lack of demos and not reading docs is that where did we put the scripts the css what happens on page load etc.  Well it’s actually been made really simple and the thing to remember is this –

Taken from the documentation

Scripting pages->Scripts and styles in the head

http://jquerymobile.com/demos/1.2.0/#/demos/1.2.0/docs/pages/page-scripting.html

When the user clicks a link in a jQuery Mobile-driven site, the default behavior of the navigation system is to use that link’s href to formulate an Ajax request (instead of allowing the browser’s default link behavior of requesting that href with full page load). When that Ajax request goes out, the framework will receive its entire text content, but it will only inject the contents of the response’s body element (or more specifically the data-role="page" element, if it’s provided), meaning nothing in the head of the page will be used (with the exception of the page title, which is fetched specifically). Please note that scripts loaded dynamically in this fashion do not guarantee a load order in the same way they would if the page was loaded via a normal http request.

This means that any scripts and styles referenced in the head of a page won’t have any effect when a page is loaded via Ajax, but they will execute if the page is requested normally via HTTP. When scripting jQuery Mobile sites, both scenarios need to be considered. The reason that the head of a page is ignored when requested via Ajax is that the potential of re-executing the same JavaScript is very high (it’s common to reference the same scripts in every page of a site). Due to the complexity of attempting to work around that issue, we leave the task of executing page-specific scripts to the developer, and assume head scripts are only expected to execute once per browsing session.

This is the key to how it all works under the hood.

So when coding a simple app in jQuery mobile in multiple pages then a simple layout might be this.  This is a simplification of the jquery mobile multi-page boiler template split across two files.

The second file does not need any of the jquery, css, or other js files.  As the navigation system looks for a div of data-role page and squirts it in.  NOTE multi-page/Multiple Page combos are not allowed it will likely fall on its face, so dont stick more than one date-role="page" into these Multiple Page designed apps.

 

Main.html

<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Multi-page template</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
<script>

   $(‘#home’).on(‘pageinit’, function () { 
       console.log(‘home page-init’);
   });

 

function Yay() {
    console.log(‘Yay’);
}

</script>
</head>

<body>

<div data-role="page" id="home">

    <div data-role="content" >   
        <h2>One</h2>
        <p>I have an <code>id</code> of "home" on my page container. I’m first in the source order so I’m shown when the page loads.</p>   

        <h3>Link to Other Page:</h3>
        <p><a href="Page2.htm" data-role="button">Show page "two"</a></p>    
    </div>
</div>

</body>
</html>

Page2.html

<!DOCTYPE html>
<html>
<head>

<title>Page Two</title>
</head>

<body>

<div data-role="page" id="two" data-theme="a">

<script>

$(‘#two).on(‘pageinit’, function () {

    console.log(‘page two pageinit’);

    Yay();  //Call a function in the parent container, cos Im just injected

});

</script>

    <div data-role="content" data-theme="a">   
        <h2>Two</h2>
        <p>I have an id of "two" on my page container. I’m the second page container in this multi-page template.</p>   
        <p>Notice that the theme is different for this page because we’ve added a few <code>data-theme</code> swatch assignments here to show off how flexible it is. You can add any content or widget to these pages, but we’re keeping these simple.</p>   
        <p><a href="#one" data-direction="reverse" data-role="button" data-theme="b">Back to page "one"</a></p>   
    </div>
</div>

</body>
</html>

 

So that being the case where do I stick the code.  Well consider it like this if its a library code stick it in the home page as that outer page is always there and loaded, however when you need stuff to happen that script should be in the page <div> as it will be loaded and injected into the main page container and executed at that point.

There are lots of other things to learn about events and injections but if you can get this bit right then the rest should just follow.

I strongly urge you to read all of the docs on jquery mobile especially around pages as understanding this navigation and the weird vood0o it does with the navigation is key to writing your code in the right place.

Categories: Uncategorized Tags:

Some Extra Notes on using Rendering Templates

October 25th, 2012 Comments off

I love rendering templates when I first came across them in WSS3 in 2008, when I started with SP 2007, I was still on 2003 until then, I thought they were brilliant it gave me a way of managing the display of a form and controlling the look and feel based in specific SharePoint groups as I could choose what fields were shown or not.

 

But the one thing I do remember is they are a bitch! to get right.  With no ability to debug those initial steps and the poor logging, even in verbose mode, going on these past two days I’ve been trying to recreate the process have been painful.

 

Luckily I found a great blog post on creating Rendering Templates that covered the basics, a lot of which I remembered but its still nice to have a guide.

    http://www.3guysonsharepoint.com/?p=987

Even with this guide there are some additional things I picked up that might help when you have a go.

 

  1. Rendering Templates live in the ROOT of CONTROLTEMPLATES folder, they wont work anywhere else so don’t even bother trying.
  2. Rendering templates, whilst they look and act a bit like ASCXs they ain’t fully, so don’t try and do any code behind in the template (this can be done in other proper user controls).
  3. Some guides show just the template in their examples, YOU NEED all the @assembly @register and @control stuff, in the guide mentioned look for the last bit of code that says "so your full template will look like this" they mean it, you need all the extra bits
  4. When it doesn’t work it just displays a blank page.
  5. ULS logs help, a tiny bit, in that it tells you it didn’t load the template

When starting off, Start VERY simple, dont bother to try and do anything fancy, just make sure your basic rendering template and registration of it are correct.

A minimum Rendering template is this, minus the @ stuff at the top (go nick this from DefaultTemplates.acx) ,this is 2007 code BTW.

<SharePoint:RenderingTemplate ID="BinaryJamListForm" runat="server">
<Template>    
    <span id=’part1′>            
    Hi         
    </span>
</Template>
</SharePoint:RenderingTemplate>

*Wire that up, see the 3guys guide above on doing that.

 

When that is done you can create a new custom user control, this is also covered in the 3guys guide but again some additional information

 

  1. Remember when developing this, you cant just copy to Hive and gac it, you need the SAFECONTROLS entry (the guide didnt mention this, probably too much 2010 dev).
  2. If it is in the GAC there is something about ascx I only learned today, when you have the @Control entry in the page you have to fully qualify the Inherits attribute, OR if you have an @Assembly reference to it instead it has to GO ABOVE THE @CONTROL reference, this got be big time, 10 yrs of coding user controls and I only just found this out.

    thx to http://blog.zebsadiq.com/post/SharePoint-Could-not-load-type-error.aspx, for setting me on the right path here, by telling me about the Control needing to be fully qualified its this that made me think my Assembly reference needed to be above, once moved my stuff worked.

Some interesting bits about creating a user control that replaces the rendering template.

This is the minimum needed to replicate the default (minus @ statments at the top)

<SharePoint:InformationBar ID="InformationBar1" runat="server" />
<SharePoint:FormToolBar ID="FormToolBar1" runat="server" />
<table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0"    cellspacing="0"     width="100%">    
<tr>        
    <td nowrap="nowrap" valign="top" width="190px" class="ms-formlabel">            
       <h3 class="ms-standardheader">                Title3 <span class="ms-formvalidation">*</span>             </h3>         </td>        
        <SharePoint:ListFieldIterator ID="ListFieldIterator1" runat="server" />         
        <SharePoint:FormComponent ID="FormComponent2" TemplateName="AttachmentRows" runat="server" />
</table>
<table cellpadding="0" cellspacing="0" width="100%">    
<tr>        
<td class="ms-formline">            
     <img src="/_layouts/images/blank.gif" width="1" height="1" alt="" /></td>     </tr> </table>
<table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px">    
<tr>        
   <td width="100%">            
       <SharePoint:ItemHiddenVersion ID="ItemHiddenVersion1" runat="server" />                
       <SharePoint:ParentInformationField ID="ParentInformationField1" runat="server" />           
       <SharePoint:InitContentType ID="InitContentType1" runat="server" />                
       <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&nbsp;"                 runat="server">                
           <template_buttons>
                <SharePoint:CreatedModifiedInfo ID="CreatedModifiedInfo1" runat="server"/>  
            </template_buttons>                
            <template_rightbuttons>
              <SharePoint:SaveButton runat="server"/>
              <SharePoint:GoBackButton runat="server"/>
           </template_rightbuttons>            
        </wssuc:ToolBar>        
    </td>    
</tr>
</table>
 

 

It’s the Control

      <SharePoint:ListFieldIterator ID="ListFieldIterator1" runat="server" />

that does all the magic and it has some great properties you should explore, hiding fields, what mode am I in.  If you choose to put your on fields on the form then If they are placed above the Field terator then the Iterator will not show them again.  If you want your custom version below the Field Iterator then add yours to the excludefields property and then add it underneath.

Or alternatively you could take full control of the form and do your own thing for eery field, but then of course new fields will not be added to your custom for.

There are different types of field iterator, I think Survey has its own.  Or you could inherit and create your own of course.

This is the default example of how to add your own field, imagine this block immediately above the FieldIterator.

 

<tr>        
   <td nowrap="nowrap" valign="top" width="190px" class="ms-formlabel">            
      <h3 class="ms-standardheader">Title3 <span class="ms-formvalidation">*</span></h3>          
   </td>        
<td valign="top" class="ms-formbody" width="400px">            
     <SharePoint:FormField ID="FormFieldTitle3" TabIndex="1" FieldName="Title3" runat="server"  />            
     <SharePoint:FieldDescription FieldName="Title3" ID="FieldDescription3" runat="server" />            
     <SharePoint:AppendOnlyHistory FieldName="Title3" ID="AppendOnlyHistory3" runat="server" />        
   </td>    
</tr>

 

Of course you can add custom validators here and jQuery etc.

If your custom form needs to set values that it looks up and is not on the Form then you will have to override the SAVE button and user your own.  Inherit from    Microsoft.SharePoint.WebControls.SaveButton.  This is a post in it’s own right so I’ll skip this bit.

In your event Save Clicked on your inherited Save Button then you have to set the list item values this is done like this

   SPContext.Current.ListItem["Description"] = myLookedUpValue;

Nothing else to do the base classes handle the rest of the save.

 

Lastly every guide discusses how you can wire up the template using list defs and content type defs and feature activations on a Content type.

BUT, you can simply edit the Form pages in SharePoint Designer, Look at the ListFormWebPart, it has a property <TemplateName>  this can be set (at least in 2007 ) to your custom rendering template.

Obviously the best way of doing this is to attach to a content type, but if like me you are having to back fit something someone else creating its a handy option to have, hope it still works in 2010, to property is still listed so fingers crossed.

Categories: Uncategorized Tags:

Connecting the VM’s to the Internet, but still hiding them from enterprise

May 29th, 2012 Comments off

For those users on a corporate network that need an active directory and need to keep it hidden from the corporate network, setting your VM network to internal will do this as will private.

The added advantage of setting things to internal means that the Host machine can access the internal network also, but none of the AD traffic or broadcasts from the internal machine get out onto the wider corporate network.  There may be one or two exceptions.  If you have a shared folder on the host machine so you can copy files to the internal machines it will authenticate against the corporate network (unless you granted everyone rights, you did ? really?).  That authentication is relayed from the host to the corp network.  One of millions of auth requests on your network, so if you’re trying to hide there is some safety in numbers, unless you’re on the MOD network or similar, they will send the marines in to get you.

 

imageThe other advantage of Internal network over private is that you can run a proxy server on the host, this proxy server can be something as simple as fiddler or tcp-trace, again standard dev tools, nothing to see here.  By running fiddler with allow remote computers to connect, any machine with it’s WinINET proxy settings configured to point at your host machines:8080 port (or other if you set it like that) to route TCP(web) traffic via your machine it will determine where that traffics needs to go.  If your traffic is from the VM’s then it will route that traffic to the next upstream proxy/gateway to the internet (external corp machines) and like wise if one of your dev mates points at your proxy server then they can browse your internal VM webs. In order to get from the host to the internals you will need to make entries in your hosts file, fiddler has  a menu option to allow you to edit it quickly.

With all this in place and my utilisation of a custom pac script and fiddlers hosts file, other devs in my team automatically route to my fiddler when they type in the address http://simonssharepoint.simon.devlan.local because the pac file directs them to my fiddler, fiddler knows to direct to the internal machine as it has a host entry for it, the AAM handles the name, all without going anywhere near the corporate DNS server, I can of course add that url to my internal VM’s DNS entries.  Also my VM’s can access the internet as the DNS server forwards to the host dns server, forwards to the corp dns server (with 8.8.8.8 as a backup) and then all IP traffic routed through fiddler on the host machine to the internet.  The only thing I cannot do is access file shares from the outside world to the inner VM’s and vice versa.  I have to copy stuff onto the host and off to the VM or external when doing file copies, opening that protocol exposes all sorts of things and is a big “LOOK AT ME IM IN YOUR INTERNETZ”.

One of the config problems we hit was the internal network was registeringimage itself into DNS, this caused issues when I wanted to MSTSC onto my host machine and it returned a 192.168.1 address, which of course the corp network machine could not locate and its a big HELLO i’m on your corp network, doing weird stuff. So to make sure your internal machine does not do that you need to untick the option that does that.

To get to this advanced TCP/IP settings, on your virtual network card select the properties, select IPv4 properties->Advanced->DNS tab.  Untick that register in DNS option at the bottom.

The other belts and braces option you need to change, once unregistered this shouldn’t be necessary but, we should set the priority of the network device to be the physical, it may not be.

image So in the Network Connections window on the menu locate the Advance settings option.

In this next dialog you can set the  order in the top box.  In the example shown here, the “Physical LAN card” is the actual NIC, this is used by HyperV as a switch so this is not the one we want.  The “LAN” option is the virtual network attached to the Physical (corporate) side of the networks and this should be imageat the top of the priority list.  The others shown “Local Area Connection” is my unused secondary physical NIC that can be ignored. The last being the DevLan.Local which is the virtual network on the Internal side.

 

 

 

 

 

 

 

 

 

 

 

 

If you have managed to register the 192… range address in DNS, and you will know this because no-one can connect to your machine on your main network or they ping you and the 192 address is unreachable, well you can fix this.

After you corrected all the DNS and IP things as discussed above

In a CMD prompt window type

ipconfig /registerdns

IF you are having trouble from another computer as it hasnt refreshed its DNS tables then you can on that machine

ipconfig /flushdns

This should clear the machine and force a refresh of your newly registered correct IP addresses.

 

There is one more thing I’m investigating regarding VPN access but until I prove it I’ll leave it out but I will add to this later as this might effect the IP address range you choose*.

*Still investigating this, but essentially, most peoples home network is on an IP address range of 192.168.1.n so as your local machine has been configured to have its internal network also configured in this range, Im told the reason I might not have been able to connect over VPN is the the return address (despite all the NAT things going on) is in the 192.168.1.* range and therefore the routing table of the main company “host” machine says I know how to route there and sends all traffic that should be going to your home machine over the VPN to the internal network.  This all sounds dubious to me and I most likely had problems because of the IP address in DNS and IP is intelligent enough to route the VPN traffic back over the VPN and the VPN will know to send it back to the client.    I have some testing to do now my DNS is fixes using a 192.168.1.* and a 192.168.2.* range set on my home machine and see if both can VPN in.

 

Technorati Tags: ,
Categories: Uncategorized Tags:

CEWP – Making Use of Coin Slider II – SPServices Version

January 31st, 2012 Comments off

Part II of the blog posts now, adding a quick tweak to auto populate the images from an ImageLibrary.

In the last post we created all the elements needed for this next piece, if you have that working then great.

First a couple of things

Get the latest SPServices version be sure to match the versions correctly especially where jQuery 1.7 and SPServices versions are concerned, changes in jQuery caused some problems in peoples libraries.  Put that library in the place you like to store them (_layouts, portal root, site collection, doc lib which ever I stuck it in my SPFolder in the site collection)

Add a new field to your Image Library, a checkbox and call it active.

Paste this code (after you modify the include statements to point at the places you stored them).

 

I haven’t put any error trapping in this code or loading pictures or messages to say activate at least one image you idiot but you can and I would if this was going on a real site. You could extend this code to get descriptions from the image library and if there was one add it to the slider text.

 



<link rel="stylesheet" href="/sites/SliderDemo/jQueryExtras/coin-slider-styles.css">
<script src="/sites/SliderDemo/jQueryExtras/coin-slider.min.js"></script>
<script src="/sites/SliderDemo/jQueryExtras/jquery.SPServices-0.7.0.min.js"></script>


<div id="gamesHolder" style="width:468px; height:280px; overflow-y:hidden">
    <div id="games">
    </div>
</div>

<script>jQuery(function($) {
 
    $().SPServices(
       {         
         operation: "GetListItems",         
         async: true,         
         listName: "ImageLibrary", 
         CAMLQuery : "<Query><Where><Eq><FieldRef Name='active' /><Value Type='Boolean'>1</Value></Eq></Where></Query>",        
         CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='ows_FileRef' /></ViewFields>",         
         completefunc: function(data) 
           {
                var theMiddle="";
                $(data.responseXML).find("z\\:row, row").each(function(){
                    var getimage= "/" + $(this).attr("ows_FileRef").substring( $(this).attr("ows_FileRef").indexOf("#") +1 );

                    theMiddle +='<a href="' + getimage + '" target="_blank"><img src="' + getimage + '" alt="' + $(this).attr("Title") + '" /></a>';

                });

                $(theMiddle).appendTo('#games');
                $('#games').coinslider({ hoverPause: false, height:246, width:618});

            }
       }
    ); 


});
</script>

Categories: Uncategorized Tags:

CEWP – Making use of Coin Slider jQuery

January 31st, 2012 Comments off

This post is how to use a small jQuery library within a CEWP to provide sliders.

First some pre-reqs.

Download jQuery (latest) and Coin Slider jQuery plugin.

Place the jQuery library in a

Choose one.

  • SPFolder
  • _layouts
  • Document Library
  • Any old web you have access to

 

You need to choose a location, I prefer master pages and putting things in _Layout, but if you dont have access to the server then you could utilise SharePoint Designer to create a folder in a site collection, again here I prefer the top top top  level Site Collection so that anywhere I use this the same js files come from the same place and get cached.

Place the CoinSlider CSS and JS files either in the same location (not master page though) or perhaps in the local site collection you are about to create this content in.

In my Code example I have already a jQuery in my masterpage, so I dont load it again.  I put the other files in an SPFolder in the site collection call jQueryExtras, you can reference them  from where you put them.

 

Next you need an Image Library, just create one somewhere, ideally unique for the content you are to display, as later on I might get to publish the next article that loads the images using SPServices, but then I might not.

In this image library place the images you want to slide, these should ideally be “landscape” style better still CinemaScope style. Those long thin pictures just work better in sliders. All these images MUST be the same size.

I used images from another sliders content (the nivo slider which I struggled to get to work, it was just easier than trying to find content) you could use images from your own stock or the demo just remember to change the image sizes in the right places (css/js).

Now that you have your JS and CSS includes in your locations and your image library populated with images we can create a CEWP, so on the page you want this go create one and hit the EDIT Source Editor

 

Paste this lot in, it is important that you set the height and width in the javascript to match your images, if you don’t expect lots of formatting issues. I tried this on MOSS and in IE7+ it wornt work in IE6, which is a pain for me as I have to find another slider now.

 <link rel="stylesheet" href="/sites/SliderDemo/jQueryExtras/coin-slider-styles.css">
<script src="/sites/SliderDemo/jQueryExtras/coin-slider.min.js"></script>

<div id="gamesHolder">
    <div id="games">
       <a href="http://www.binaryjam.com/" target="_blank">
          <img alt="Wall-E" src="/sites/SliderDemo/SliderImages/walle.jpg"> 
          <span><b>Wall-E</b><br>A Film about a robot. </span>
       </a>
       <a href="http://www.binaryjam.com/" target="_blank">
          <img alt="Finding Nemo" src="/sites/SliderDemo/SliderImages/nemo.jpg"> 
       </a>
       <a href="http://www.binaryjam.com/" target="_blank">
           <img alt="Toy Story" src="/sites/SliderDemo/SliderImages/toystory.jpg"> </a>
       <a href="http://www.binaryjam.com/" target="_blank">
           <img alt="Up" src="/sites/SliderDemo/SliderImages/up.jpg"> </a>
    </div>
</div>
<script>jQuery(function($) {
	$('#games').coinslider({ hoverPause: false, height:246, width:618});
});
</script>

<!-- -->

<!- Force Stupid blog code window to be bigger -->

<!-- -->

Have fun

Categories: Uncategorized Tags:

Error When talking to SharePoint Web Services in code

January 4th, 2012 1 comment

I’ve been trying to talk to SharePoint’s web services in C# for a couple of hours now. Something I do in JS all the time, but rarely in a clients C# app.

I’ve been getting the same error over and over again, but keep getting an error when trying to do anything.

Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).

I had dutifully copied the example code from the MSDN site and got a web reference to the Lists Web Service of course

and commented out the URL code in the example because that points at their site, not mine, which is pointed to by my web reference.

/*Set the Url property of the service for the path to a subsite.*/ listService.Url = http://MyServer/sites/MySiteCollection/_vti_bin/Lists.asmx;

WRONG!!!!!

If you are getting this error then it is because you commented out the URL.

When you add a web reference you are adding a WSDL file which is then compiled.  The WSDL is not specific to your site location,

if you open up the WSDL XML the section right at the bottom is pointing to elsewhere, the root of the WebApplciation not the RootWeb / Site you are interested in.

<wsdl:service name="Lists">     <wsdl:port name="ListsSoap" binding="tns:ListsSoap">       <soap:address location="http://my.binaryjam.com/_vti_bin/lists.asmx" />     </wsdl:port>     <wsdl:port name="ListsSoap12" binding="tns:ListsSoap12">       <soap12:address location="http://my.binaryjam.com/_vti_bin/lists.asmx" />     </wsdl:port>
</wsdl:service>

You need that line in the code that sets the listService.Url value, without it you are going to go mad trying to track down this bug, cos I didn’t find the answer online, I had to use fiddler.  Of course this article will now exist. :-)

 

Categories: development, Sharepoint Tags:

Embracing the dark side – Part 3, Image browser enhancement to a form

December 20th, 2011 Comments off

Continuing from the previous post, Customising a List form, we are now at the point when we can start to do something useful with these techniques as let’s face it adding hello world to a form doesn’t really add value.

So in this post I am going to add a customisation to make the input forms new or edit a little more useful and therefore encouraging user adoption.

Have you ever used the URL field ?  Perhaps formatted as a picture ? It looks like this on the form

Normal Picture Link

The absolute height of usability that one. Is it better in 2010, my other dev box is off at the minute. Thing is we can make this better.  In my scenario the user needs to select an image from an existing Image Library.

By providing the users with an extra “button” we can add some javascript to give them the ability to browse the image library right there in the add new item page (or edit) and select the image, no messing about cut and pasting urls, which for some users is just a little too much for them to deal with. Instead they See a picture like this to pick an image from

CropperCapture[10]

 

Below you can see the added hyperlink, the picture field populated and a preview image.

The more observant will notice this version picks thumbnails automatically.

CropperCapture[9]

The code to do this relies on jQuery being included in a master page, if you do not do this by default in your SharePoint implementation, then

  1. Consider doing so
  2. If not, you can always add a script tag referencing it in directly in the page

The example code below relies on you determining certain things and setting the code constants to the values you have determined, e.g. the Image List Name and Guid, the jQuery field selector for the picture block, this is something that can only be done by rendering the form and figuring out the ID of that first text box of the field.

In my example the jQuery selector is

 </p> <p>var pictureFormFieldSelector='input[id$="UrlFieldUrl"]';</p> <p>

Which locates an input box with the ID ending in “UrlFieldUrl”. The Real name, in my case, happens to be “ctl00$m$g_df4349ae_3a85_4882_93ef_c7c49eb75719$ctl00$ctl04$ctl07$ctl00$ctl00$ctl04$ctl00$ctl00$UrlFieldUrl”.

I use that tag to automatically add the HTML for the “Click Here” link and determine the layout of the page for adding the preview Image.

The code for the Dialog Picker is Standard SharePoint, the Asset Picker, and I took the idea from a blog post , in this chaps blog he is using it on a toolpart.

       http://fahadzia.com/blog/2009/11/using-sharepoint-image-picker-to-select-images/

 

So here is the code I use to implement this in a page.

<script>

 

//NoConflict is enabled in my environment
//Pass to documentLoad this function 
jQuery(function ($) {

    //Constants that refer to the Image List
    //an attempt to generalise this code, fingers crossed
    var baseUrl=L_Menu_BaseUrl;
    var imageListName=”MyImageList”;
    var imageListGuid=”{F406F2AA-5518-4E46-86F5-9CDDC5CF8F38}”;
    //This is the jQuery selector to identify the specific Picture Block we are to target
    var pictureFormFieldSelector=’input[id$="UrlFieldUrl"]‘;
    //Grab the Form Element Block,
    var $formBlock=$(‘#onetIDListForm’);
    if ($formBlock.length>0)
    {

        $(pictureFormFieldSelector).parent().prepend(‘<input id=”findThatTxt” type=”hidden”>Click <a href=”#” id=”advancedBrowse”>here</a> for advanced browse</span><br/>’);
        with(new AssetPickerConfig(‘myAssetPickerObj’))                                            
        {{                                                 
            DefaultAssetImageLocation=’~SiteCollection/’ + imageListName;                                                 
            CurrentWebBaseUrl=baseUrl;                                                 
            OverrideDialogFeatures=”;                                                 
            OverrideDialogTitle=”;                                                 
            OverrideDialogDesc=”;                                                 
            OverrideDialogImageUrl=”;                                                 
            AssetUrlClientID=’findThatTxt’;                                                 
            AssetTextClientID=”;                                                 
            UseImageAssetPicker=true;                                                 
            DefaultToLastUsedLocation=false;                                                 
            DisplayLookInSection=true;                                                 
            ReturnCallback = null;
        }}
        $(“#advancedBrowse”).click(function() {
            APD_LaunchAssetPickerUseConfigCurrentUrl(“myAssetPickerObj”);
            if ( $(‘#findThatTxt’).val()!=”” )
            {

       var imageLocation = $(‘#findThatTxt’).val();
       var urlStart = document.location.protocol + “//” + document.location.host;
       var finalImg = urlStart + imageLocation;
       var editPoint = imageLocation.lastIndexOf(“/”);
       var previewImg = urlStart + imageLocation.substring(0, editPoint) + “/_t/” + imageLocation.substring(editPoint + 1).replace(/\./g, “_”) + “.jpg”;

                $(pictureFormFieldSelector).val(previewImg);
                if($(‘#previewImg’).length==0)
                {
                    $(pictureFormFieldSelector).parent().append(‘<IMG id=”previewImg” src=”‘ + previewImg+ ‘” />’);                          
                }
                else
                {
                    $(‘#previewImg’).show();
                    $(‘#previewImg’).attr(“src”,  previewImg);
                }
            }
            else
            {
                $(pictureFormFieldSelector).val(“”);
                if($(‘#previewImg’).length>0)
                    $(‘#previewImg’).hide();
            }
            return false;
        });
    }
});

 

</script>

Categories: Uncategorized Tags:

Embracing the dark side – Part 2, Customising a List Form

December 15th, 2011 Comments off

SPD

There are many things that Designer can do and I’ve seen many an article on DVWP but what I didn’t know, until I saw @sympmarc do it, was customising a List form in designer, something I’ve done in Studio before with rendering templates etc but never seen it done on-the-fly as it were.

Where to start ?

Well designer of course, but what do I mean by that, what’s the best approach to do this ? Is there one. Yes, I think so and I got clues as to what I think this should be at SharePoint Saturday.

First we need somewhere to play so create yourself a test site and a list, create a few fields, it doesn’t matter what as this first post is just about how to go about editing a form.

image

Now open the Site in Designer, if you’ve never done this then a dialog will open and you have to select your site from the list you can see, or navigate to it somehow, but easiest is to just cut and paste the Site Collection URL into the box and click open, do not put a filename, so that default.aspx you pasted in there, just scrub that out. Great.

 

Now in Designer you should have your site collection open and in the Folder window, if you cannot see it hit Alt-F1, you can see the structure of your site.

image

Expand the Lists folder and the list itself and you should see something like this.

Here you can see two of my lists one stupidly named based on an announcements list, but key to what we are about to do you can see the specific pages of the forms associated with this list underneath the list itself.

This is what we are going to change.  First we are going to make a slight change to the NewForm.aspx.  BUT for safety sake we are not going to edit the original, you might make a mess, we are going to make a copy of it to make our changes and then make sure the list points at this version, then we can always switch it back.

So to do this, counter-intuitively open the NewForm.aspx by dbl clicking it now immediately “Save As” and type in the name AdvancedNewForm.aspx (or whatever you think suits your needs).  You could of course edit any of the forms like this.

Doing this (should) do two things, first it will make a copy of the new form under the list, but importantly it should have set the default form for an item to be our new version. 

 

imageYou need to check this has happened, so right click the List in the folders windows and select properties. Now click the tab Supporting Files, the new item form should be pointing at your AdvancedNewForm.aspx.  If it is not then you can select it.

You do this by

N.B.Important step easily missed

   1. Select the Content type specific forms option for ITEM from the combo box

   2. For your new item form select the browse button and navigate to your selected form.

 

If you do not do step 1 then it will look like it worked but then refuse to change the item and you will go mad trying to figure out what is going on, cos designer will not tell you you’ve done it wrong.

 

Our new page should be open in the main window of designerimage by default it should be a split window for those happy with code and design surfaces, if you need to change this view at the bottom of the window is an option to imagechange this, it’s easily missed so I point it out here.

 

 

Now in the code look for

    <asp:content runat="server" contentplaceholderid="PlaceHolderMain">

 

 

After this we are just going to put some text to customise our form, “Hello Word”, enter imagethis text and save the form.  Go back to your site in a browser and click new on your list and you should see the custom form now and not the original. Not the most exciting example but this describes the process of doing that customisation.

 

 

 

You will be doing far more complicated customisations than this eventually, but it’s important to note how to start doing this.

For those devs amongst you this will go against the grain as directly editing source code on a live system with no Source Code Control. 

For every one there are some other practices you can learn from here where I made some mistakes and have paid for it in losing my changes.

Firstly when developing a complex solution for your form, DONT do it on live, take a copy of what you want to change a develop it on another site, on a dev machine, wherever just not on the live one, unless of course its not actually in use at the time you are doing it.

Secondly, if you have Visual Studio and TFS or other editor and source code control, take a copy of the changes and save them into a file under your TFS project and do checkins or create multiple copies called version 1,2,3 etc.  DONT just have your only copy in SharePoint.  I lost a lot of work when I mistakenly deleted a dev site collection of mine.

Just because this is an easy approach to developing don’t treat it as such. For each demo or customisation create a new properly named site collection that matches your TFS project, don’t call your site collection test you might delete it.

That’s it for this post.  A Simple guide on editing those custom forms in designer with a few tips to make sure you don’t mess up.

 

 

 

 

 

 

Categories: Uncategorized Tags: