Archive for September, 2009

11
Sep
09

Cascading Drop-downs in a SharePoint Custom Task Form

I’m documenting my journey into a land where I’m not completely comfortable…javascript.  While I have been a software developer and DBA at times during my career, it’s been a while since I’ve had to do much with javascript.  So, like one of my students recently said, “I code in Google.NET.” 

A client had a requirement for cascading drop-down menus and found a great post by Marc Anderson about cascading drop-downs on a SharePoint form.  In fact, Marc’s turned it into a three-part series, culminating in a jQuery library for SharePoint Web Services.  I tried helping him implement part one and part two without much success.  There seems to be a real problem with the javascript function getElementsByTagName in IE and it not returning a correct array of objects when it’s called…e.g. getElementsByTagName(“td”).  So, after spending five or six hours not getting anywhere, I decided to try the jQuery library version. 

First, you need to get a copy of jQuery.  You can do that here.  This needs to be referenced in your code.  A simple way to do this is to create a document library in SharePoint and upload your javascript files.  Of course, the library must be able to be read by anyone using the code.  You can see the library I set up and jquery-1.3.2.min.js that has been uploaded (along with other things).

image

Then you need to get a copy of the SPServices jQuery library and upload it.  It is out on CodePlex here

In the code window in SPD, you can reference the libraries thusly:

<script language="javascript" type="text/javascript" src="http://portal.awbikes.local/SiteDirectory/wf/JS/jquery-1.3.2.min.js"></script>

<script language="javascript" type="text/javascript" src="http://portal.awbikes.local/SiteDirectory/wf/JS/jquery.SPServices-0.2.8.js"></script>

Important Note

It is important to note that I’ve found that the order in which the libraries are referenced is important!  So important that, if they are reversed, you’ll likely get an “‘SPServices’ is null or not an object” error.  This was plaguing me for several hours.

Here’s a picture.  Click on it to make it bigger.

image

Then you have to “call” the javascript function.  It was recommended to me to use the document.ready syntax. 

<script language="javascript" type="text/javascript">
$(document).ready(function() {
        $().SPServices.SPCascadeDropdowns({
        relationshipWebURL: "
http://portal.awbikes.local/SiteDirectory/wf",
        relationshipList: "SubServiceTypes",
        relationshipListParentColumn: "Title",
        relationshipListChildColumn: "SubServiceCategory",
        parentColumn: "AM Sub Service",
        childColumn: "Sub Service Category"
        });
    });
</script>

Again, a picture of the code.

image

relationshipWebURL

The relationshipWebURL can be left blank as long as the relationshipList is in your site.  Otherwise, specify the URL of the site that has the relationship list.

relationshipList

The relationship list is a simple list with two columns that indicates what the allowable values are (column2) for each value in column1.  So, if you a relationship of Country/State, you’d have to list a country many times (50 for the U.S.) and enter a unique state on each line.  If you had two countries (U.S. and Canada), each time a country is selected in the primary drop-down list, the secondary drop-down would populate with the list of states (or provinces) valid for the selected country. 

relationshipListParentColumn

The relationshipListParentColumn is the internal name of the primary or first column in the relationship list.  The internal name can vary greatly from the displayed name.  Usually, if you put spaces in a column name, you’ll find the spaces are replaced by _X0020_, but you also have to be careful about other liberties that SharePoint takes when creating internal field names.  To view the internal field name, go to the list settings and click on the column name.  You can look at the end of the URL and see the internal field name where it says &Field=XXXX.  Here’s an example.

image

You’ll also see the underscores and other “unsafe” characters have been URL-encoded.  %5F is the encoded version of the underscore (_) character.  So, AM Sub Service becomes AM_x0020_Sub_x0020_Service.

relationshipListChildColumn

The relationshipListChildColumn is the column that will change and be filtered based on the selection of the parent column.  Similar to the parent column, you need to specify the internal field name for this column.

parentColumn

The parentColumn is the display name of the parent drop-down list on the form.  You can find this in the form in code view in SPD.  This corresponds to the title of the control.  If you use the IE developer toolbar (for IE7 or prior versions), or use the built-in developer tools in IE8 (F12), you can find the properties of the control, including the title.  Here’s IE7 with the “Find by Click” function enabled in the developer toolbar.

image

You can also look in the code view in SPD and find the <datafields> tag.  Here you’ll see a listing of all the data fields’ internal and friendly names.  Here you can see AM_x0020_Sub_x0020_Service_x0020 and AM Sub Service 1.  I’m not really sure where the ending “1” went on the internal name…must be a SharePoint weirdness.

image

childColumn

The childColumn is similar to the parentColumn except it’s the one that get populated based on the selection of the parent column.  You need to specify its friendly name or title.

image

Again, looking at the <datafields> tag you can see Sub_x0020_Service_x0020_Category and Sub Service Category as the internal and friendly field names.

image

My Problem

My problem was I was receiving a “‘SPServices’ is null or not an object” error whenever I tried to use the code.  Here’s what the debugger was showing from within the executing code.

clip_image001

It turns out that the problem was resolved by changing the order of the script references as stated previously in this post.

Application

Now, on to the fun stuff.  Here we are, in a SPD workflow using the “Collect Data From a User” action.  This action creates a custom task form that is used to “collect” (imagine that) data from a user when the workflow creates a task and pauses for task completion.  We want to use the cascading fields within the custom task form.

image

Within the workflow I’ve opened up the custom task form that was created by the action in the workflow. 

image

It is within the PlaceHolderMain area I’ve strategically placed the code that will control the drop-down lists.

image

Executing the Edit task function which uses the custom task form, you can see that I have success!

image

image

In the application of cascading drop-down menus on a custom task form I still have one problem to resolve.  When I complete the task, an unexpected error occurs.  In thinking about this, I’m wondering if this might be caused by the extra values added by the javascript not being accounted for by the form.  I still need to check this out and determine the source of this error.

image

11
Sep
09

Using Topaz Signature Pads to Capture Signatures for InfoPath 2007 Forms

This is a great solution created by Richard Wixom, whom I’ve worked with over the years.  Richard is the president and owner of DNSalePrice.com.  He spends a lot of his time buried in algorithms deciphering the goings on in the domain name industry and creating huge databases with information about domain names.  We collaboratively worked on this solution and thought it was an interesting exercise that others might appreciate.

TOPAZ Signature Pads can be enabled for InfoPath 2007 with the signature image then stored and embedded within the InfoPath form. The following approach uses C#/.Net managed code with the code and appropriate DLL’s embedded within published InfoPath forms. Standard InfoPath features such as email distribution, SharePoint storage, etc. are available for InfoPath client. Web-enabled InfoPath forms are not supported.

Prerequisites for enabling TOPAZ Signature Pads with InfoPath 2007:

1. TOPAZ signature pad hardware and software installed.

2. Security level for InfoPath form set to Full Trust and signed.

3. Programming language for InfoPath form set to “C#”

4. Compatibility for InfoPath form and “Design form template that can be opened in browser” is not set.

5. Local access to the C# SigPlusNET assembly. This can be found in the Topaz’s “SigPlusNETDemoCSharp” download that is available here.

Setup requires three steps:

1. Adding the required controls to InfoPath form

2. Adding DLL reference to code

3. Adding required code

Estimated time to complete should be under five minutes.

Add Required Controls

In “Design” mode, create a new InfoPath form and verify/set settings as stated in “Prerequisites.” Add two Buttons, a Text Box and a Picture control to the form. Use a layout similar to the following:

clip_image002

Set the control properties on the first button (Label and ID) as shown below. Both C# and XML are case-sensitive languages so be sure to use the same letter case as shown.

clip_image004

Set the control properties for the second button as shown below:clip_image006

For the Text Box properties, under Data tab, set Field name as shown below:

clip_image008

For the Text Box properties, Display tab, check “Read-only” as shown below:

clip_image010

For the Text Box properties, Size tab, set size values as shown below:

clip_image012

For the Picture properties, under the Data tab, enter Field name as shown below and uncheck the box to “Allow the user to browse, delete, and replace pictures.”

clip_image014

Under Tools/Programming, open Microsoft Visual Studio Tools for Applications. In the Project Explorer (see tabs on right), right-click on “Reference”, select “Add Reference” and add the following two references:

1. Under the .Net tab, locate and add “System.Drawing”.

2. Under the Browse tab, navigate the full path to SigPlusNETDemoCSharp (see Prerequisites) and add “SigPlus.dll”.

Project Explorer should now look like the following (see highlighted reference):clip_image016

Now cut and paste the following replacement code over the default code — EXCEPT you will need to preserve the default namespace that is provided. The following is an example of the default namespace that you’ll need to preserve when pasting the replacement code.

clip_image018

Replacement code:

using Microsoft.Office.InfoPath;
using System;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using mshtml;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace _0900_A_with_Signature ç [retain the default value here]
{
public partial class FormCode
{
internal Topaz.SigPlusNET SigPlus = new Topaz.SigPlusNET();
// NOTE: The following procedure is required by Microsoft Office InfoPath.
// It can be modified using Microsoft Office InfoPath.
public void InternalStartup()
{
((ButtonEvent)EventManager.ControlEvents["Button_Sign"]).Clicked += new ClickedEventHandler(Button_Sign_Clicked);
((ButtonEvent)EventManager.ControlEvents["Button_Done"]).Clicked += new ClickedEventHandler(Button_Done_Clicked);
}
public void Button_Sign_Clicked(object sender, ClickedEventArgs e)
{
SetSignatureImage(String.Empty);
SetTopazMessage("Sign on signature pad and then click \"Done\".");
SigPlus.SetTabletState(1); //tablet on
SigPlus.ClearTablet();
}
public void Button_Done_Clicked(object sender, ClickedEventArgs e)
{
SigPlus.SetTabletState(0); //tablet off
SigPlus.SetImageXSize(400);
SigPlus.SetImageYSize(100);
SigPlus.SetImagePenWidth(11);
SigPlus.SetJustifyMode(5);
Image sigImage = SigPlus.GetSigImage();
String sigBase64 = ImageToBase64(sigImage, ImageFormat.Jpeg);
//verify signature entered and read
if (sigBase64.Length > 2000)
{
SetSignatureImage(sigBase64);
SetTopazMessage(string.Empty);
}
else { SetTopazMessage("Signature not recoginized. Please verify signature pad, then click \"Sign\" button and follow instructions."); }
}
public void SetTopazMessage(string message)
{
string XpathForTopazMessage = "/my:Fields/my:TopazMessage";
XPathNavigator messageField = this.MainDataSource.CreateNavigator().SelectSingleNode(XpathForTopazMessage, NamespaceManager);
messageField.SetValue(message);
}
public void SetSignatureImage(string base64Image)
{
string XpathForSignatureImage = "/my:Fields/my:SignatureImage";
XPathNavigator imageField = this.MainDataSource.CreateNavigator().SelectSingleNode(XpathForSignatureImage, NamespaceManager);
DeleteNil(imageField); //remove xsi:nil attribute
imageField.SetValue(base64Image);
}
public string ImageToBase64(Image image, ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
public void DeleteNil(XPathNavigator node)

{

if (node.MoveToAttribute("nil","http://www.w3.org/2001/XMLSchema-instance&quot;))
{
node.DeleteSelf();
}
}
}
}

Click on “Build” and verify that your template builds without programming errors. If you encounter any errors, correct as required. The most common error will be incorrect entry of control ids as noted above.

Save your source files, close Visual Studio for Applications, add required content and controls to your InfoPath form and publish.

08
Sep
09

Error Updating List Item in SharePoint Designer Workflow – KB932394

A.K.A. – A timer does not resume operation after a workflow is reloaded in Microsoft Windows Workflow Foundation

Here’s something that’s kind of hard for me to believe.

I’ve been working on an SP2 patch-level SharePoint site developing some SharePoint Designer workflows.  Nothing complicated, mind you, but they will be getting much more complicated.  All I have to do is prove you can do what we need to get done with an SPD workflow. 

I’ve got 12 workflows that start automatically on creation of a list item, thus assigning 12 individual tasks.  The workflow(s) I’m creating are very simple.  They look up people based on a role from a SharePoint list.  A variable is set with the person (approver) that is looked up.  They pause until a certain day at a certain time and then each workflow executes the "Collect Data from a User" action.  There is one of these actions for each of the 12 workflows.  This essentially creates 12 tasks (in Workflow Tasks) in response to entering an item in a SharePoint list.  Pretty simple.

There is also a secondary workflow that gets spawned on each task that is created as a result of the “Collect Data from a User” action in the primary workflow.  The secondary workflow (on the Workflow Tasks list) pauses for a certain amount of time and, when the pause is over it inspects the status of the task.  If it is not complete, it updates the assigned to on the task with a backup approver.  Again, not a very complicated workflow.

The problem is that the "Assigned To" field on each of the tasks that are created in the Workflow Tasks list are not being set to the person the task is assigned to.  Many times I get 3 of the tasks that get the "assigned to" set correctly.  Some times more.  It appears to be very inconsistent.  Many times the “assigned to” field is blank (never filled out).  The history list many times shows “error updating a list item.” 

ErrorUpdatingListItemHistoryListEntry

What have I tried to get around this problem?  I’ve tried using the trick of prepending -1;# to the user name per this article.  I originally had all the task assignment actions in a parallel step in a single workflow before breaking them out into multiple workflows.  I’ve tried updating the assigned to in another workflow that is started automatically on the task.  Nothing seems to give consistent results.

Perhaps I’ve stumbled upon the root cause of all my woes.  I was searching the web and ran across this post.  This indicated that I needed the update to the Windows Workflow Foundation described in KB932394.  I know that I had seen a reference to this fix from other posts, but the actual article is from 2007.  I ASSumed, incorrectly, that this fix would be part of one of the SharePoint cumulative updates or, at the very least, a service pack.  Not so!  My original files (after SP2) were version 3.0.4203.2.

image

image

image

After applying this patch, the file versions were 3.0.4203.201. 

image

Now, I know that TECHNICALLY the files are part of the Window Workflow Foundation, but wouldn’t you think they’d be included in a SharePoint service pack?

What other patches do I need to get to insure that declarative SPD workflows will be processed correctly?

 

 

 

06
Sep
09

Great Example of a SharePoint Designer Workflow Solving a Scheduling Problem

Ran across this on Paul Galvin’s site. 

http://paulgalvin.spaces.live.com/blog/cns!1CC1EDB3DAA9B8AA!3133.entry

Hey, what do you know, it’s one of my posts!  Thanks for the nice words, Paul!

http://sharepointsolutions.blogspot.com/2009/02/give-blood-to-your-workflow.html




Asif Rehmani’s SharePoint Videos

SharePoint-Videos

Click to access a wealth of SharePoint videos

SharePoint Rx

SharePoint Rx Home

Categories

Posts by Date

September 2009
M T W T F S S
« Aug   Dec »
 123456
78910111213
14151617181920
21222324252627
282930  
Support Wikipedia