Archive for Uncategorized

jQuery and Sharepoint Web Services: GetListItems with queries

// November 23rd, 2010 // No Comments » // Uncategorized

I recently did another post, detailing deleting a list through the use of Sharepoint Web Services. In this post ill give you a codesample on how to query a list using the item ID and the list name.

The business case for this, was to add a context menu item based on an item property, in my case, document status. Manipulating context menu items is a long winded process, one which is best read in posts such as this post or another post here

Essentially this method was called just before the item is added to the context menu item, it is intercepted at the Custom_AddListMenuItems method which allows you to add list menu items. In the method below, i use the local ID of the conext menu item clicked, together with the list guid (ctx.listname) and i query the list for the document status of that item.

I only add the menu item when docstatus is not equal to published. Another interesting note is the ajax call is done synchronously which forces the program halt execution until the ajax call has received a response from the web service.

 Javascript |  copy code |? 
01
02
function ShowModerationHistory(currentItemID, r, t, m, v, y) {
03
 
04
    var returnValue = false;
05
    var soapEnv =
06
            "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'> \
07
                <soapenv:Body> \
08
                     <GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
09
                        <listName>" + ctx.listName + "</listName>" +
10
			            "<viewFields>" +
11
			            "<ViewFields>" +
12
		                    "<FieldRef Name='DocumentStatus' />" +
13
			            "</ViewFields>" +
14
     			        "</viewFields>" +
15
                            "<query>" +
16
			                    "<Query>" +
17
                                    "<Where>" +
18
                                    "<Eq>" +
19
                                    "<FieldRef Name='ID' />" +
20
                                    "<Value Type='Integer'>" + currentItemID + "</Value>" +
21
                                    "</Eq>" +
22
                                    "</Where>" +
23
                                "</Query>" +
24
                            "</query> " +
25
                        "</GetListItems> " +
26
                    "</soapenv:Body> " +
27
                "</soapenv:Envelope>";
28
    $.ajax({
29
        url: SP.PageContextInfo.get_webServerRelativeUrl() + "/_vti_bin/lists.asmx",
30
        type: "POST",
31
        dataType: "xml",
32
        data: soapEnv,
33
        async: false,
34
        complete: function (xData, status) {
35
            var docStatus = $(xData.responseXML).find("z\\:row:eq(0)").attr("ows_DocumentStatus");
36
            if (docStatus != null && docStatus != undefined) {
37
                if (docStatus.toUpperCase() != "PUBLISHED") {
38
                    x = CIMOpt(r, t, m, v, null, y);
39
                }
40
            }
41
        },
42
        beforeSend: function (xhr) {
43
            xhr.setRequestHeader('SOAPAction', 'http://schemas.microsoft.com/sharepoint/soap/GetListItems');
44
        },
45
        contentType: "text/xml; charset=\"utf-8\""
46
    });
47
 
48
}
49

The Expert News Rotator Webpart 2010

// November 17th, 2010 // 21 Comments » // Uncategorized

So its been a while since i last released this webpart, in fact more than a year. I have upgraded it to support Sharepoint 2010 and added a new feature which makes the news rotator easier to use.

The feature allows users to use an “image uploader” column when adding both the main image and the thumbnail image on the news rotator. Once the webpart has been installed, the announcements list, which hosts the news items needs to be configured in the following way (the following image shows the image uploader type column):

image uploader column

1. Create 2 columns on the appropriate announcements list – These columns should be of type “Image Uploader” and should be called “Image File” and “Image Thumb Url”.
2. The 1st image uploader column (“Image File”) should have a width set to 270px
3. The 2nd image uploader column (“Image Thumb Url”) should have a width set to 50px
4. Remember to disable attachments for this list.
5. Other configuration includes the “upload images to the following list” storage document library (where the images will be stored, along with the resized images)

Then add the webpart to the page and edit the properties of the webpart (toolpane)

1. Set “News Image URL Column” to “Image File”
2. Set “News Thumb Image URL Column” to “Image Thumb Url”

You can download this version of the webpart (2010 version) on codeplex here

.NET Required Field Validators and Client Side Validation

// September 15th, 2010 // No Comments » // Uncategorized

This little issue gets me at least once a week, and i spend at least 10 minutes finding the article that helps me everytime, or just remember what i did previously!

If your button doesnt postback (as in you submit your data on the client side), your requiredfieldvalidators will not fire and validation will not occur.

Well this helpful article over here helps me with that everytime:

http://alvinzc.blogspot.com/2006/10/aspnet-requiredfieldvalidator.html

Thanks to Alvin

jQuery and Http Posts to Sharepoint

// August 13th, 2010 // 1 Comment » // Uncategorized

My current project required me to fire an AJAX POST to provision a mysite. The provisioning was done using the built in Self Site Creation method.

I used jQuery’s ajax POST function to create a post to my code-behind method. Simple right? wrong. I ran into the infamous:

The security validation for this page is invalid. Click Back in your Web browser

Well i tried the usual tricks:

1) Setting web.AllowUnsafeUpdates = true. Didnt work
2) Tried the SPUtility.ValidateFormDigest method on the POST. Didnt work.
3) Tried the SPWebApplication.FormDigestSettings approach and set it to false, initiate the call and reset it. I frown on this approach as it does require to essentially make a change to what we would be doing in central admin in turning off the Form Digest Settings and then resetting it. Nonetheless, this did not work. I later found that updating anything “central admin” related gave me an access denied. This was due to us running our web app with claims. (SAML)

So i was stumped. I went back to basics.

I created a normal button which did a postback and called the self site create method. No problems with that POST. But a problem with my client side jQuery post.

So I then turned to Fiddler to see what the difference was between the two POST calls. Through spoofing POST calls i finally found an interesting POST variable which is passed with a normal postback generated by a button sitting within a Sharepoint context.

__REQUESTDIGEST

I did a quick google and found this post which was more than helpful. According to this post the variable is:

nothing more than a hidden field set by the server and verified back by the server when the page is submitted. As documented by Microsoft: The purpose of form digest validation is to help prevent security attacks where a user is tricked into posting data unknowingly to a server

Read this post if you come across the problem i explain above. It really does explain this issue really well.

After reading it thoroughly i realised i just need to pass in the variable with the POST’s data when doing the AJAX call: Here’s what my jQuery ajax POST looked like in the end:

 XML |  copy code |? 
01
02
 $.ajax({
03
                type: "POST",
04
                url: "CreatePersonalWorkspace.aspx",
05
                beforeSend: function (xhr) {
06
                    xhr.setRequestHeader("Content-Type",
07
                         "application/x-www-form-urlencoded");
08
 
09
 
10
                },
11
                data: "method=CreatePersonalWorkspace&__REQUESTDIGEST=" + $("#__REQUESTDIGEST").val(), //Pass through the requestdigest on the post - necessary to execute provisionworkspace method - this is passed through on all posts
12
                success: function (msg) {
13
                    var result = JSON.parse(msg);
14
                    if (result[0].Status == "created") {
15
                        $("div[id$='provisioningDiv']").hide();
16
                        $("#personal_workspace_url").attr("href", result[0].Value);
17
                        $("#personal_workspace_url").show();
18
                    } else if (result[0].Status == "redirect") {
19
                        document.location = result[0].Value;
20
                    }
21
                    else {
22
                        $("#errorResponse").html(result[0].Value);
23
                    }
24
                }
25
            });
26

Sharepoint 2010 RTE Image Picker for the Ribbon

// July 29th, 2010 // 1 Comment » // Uncategorized

Our current project required us to make a few changes to the OOTB Asset Picker dialog. Within this dialog there is the common “Look in” pane which isnt easily customized. We required the dialog to only show certain document libraries in which only png, jpeg or gif files may be viewed. Additionally we customized the picker to be launched from the ribbon and place the returned image within the rich text editor.

This all would not have been possible without the help of Karine Bosch’s Post on Custom Dialogs.

The following is a screenshot of the end product:

The page is invoked from a custom ribbon control however this only makes a call to our custom AssetPicker dialog. The source code (elements.xml) provides a split button control which invokes the picker for both replacing and inserting images. This ribbon control element (elements.xml) replaces the OOTB “Insert Image” control, however can be customized to add the default “From Address” and “From Computer” split options at a later stage.

The LaunchPicker method in the xml file invokes the OpenDialog method which in our project has been created as an extension to jQuery. However this need not be the case. Its merely a function which calls the SP.UI.ModalDialog.showModalDialog() method with a bunch of options. Note the callback method which is specified in the LaunchPicker method. This method is called once the image has been selected; this is known as the “callback method”. Careful that you only pass “replace” or “insert” to the LaunchPicker method.

Right lets move onto the AssetPicker itself. The .aspx is pretty much the simple part simply with a method which allows the user to choose the right image and invoke the callback method. It uses a repeater control to populate the images datasource.

The code-behind features several enhancements including a paging function. The repeater control provides us with the datasource of all the images found within the choosen folder or document library itself. Note: We have used a custom document library basetemplate and populate our treeview with these document libraries. This is where you may customize the code to search for Document Libraries or Image Libraries only. Be careful not to include generic lists as the code searches for files only.

Once the image has been chosen, the pickerCallBack callback method is fired as shown in javascript file. This in turn may replace or insert an image using the InsertRTEImage or ReplaceRTEImage depending on the options you passed to the launchpicker method.

The source files are attached.

Sharepoint 2010 Ribbon Control and Rich Text Editor

// July 26th, 2010 // 1 Comment » // Uncategorized

Im currently lucky enough to be working on the 2nd largest Sharepoint 2010 deployment in the world currently! It really has been a wonderful opportunity to be exposed to some of the new Sharepoint 2010 functionalities as well as interfaces, API’s, SDK etc.

One of the latest modules for the Project is the media library ribbon control, a control which manipulates the way our users will upload images to Sharepoint.

The OOTB functionality allows users to upload images from multiple sources namely:

1) From Sharepoint
2) From Computer
3) From Address

We needed new functionality to be able to upload images using a silverlight control (activex prevents our users using Firefox which is a big problem for the 70,000 odd users!). The silverlight control also checks for banned words which wasnt available to us. The key functionality here is:

1) Replace the existing “Upload Picture” split button with ours

2) Call the Upload Image Dialog

3) Instantiate the callback method which inserts the image back into the Rich Text Editor

First up, we need to create a new module in Visual Studio 2010. This is the module which act as a replacement button for OOTB “Upload Picture” split button. Im not going to go through doing this as this is basic VS2010 functionality. The new elements.xml file is as below:

 XML |  copy code |? 
01
02
<?xml version="1.0" encoding="utf-8"?>
03
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
04
  <CustomAction
05
 Id="Ribbon.Image.Image.Edit.ReplacementButton"
06
 Location="CommandUI.Ribbon"
07
 Rights ="EditListItems" >
08
    <CommandUIExtension>
09
      <CommandUIDefinitions>
10
<CommandUIDefinition
11
          Location="Ribbon.EditingTools.CPInsert.Media.Image">
12
          <SplitButton
13
                  Id="Ribbon.EditingTools.CPInsert.Media.Image.ReplacementButton"
14
                  Alt="$Resources:core,ButInsertImageAlt;"
15
                  Command="InsertImage"
16
                  CommandMenuOpen="InsertImageMenuOpen"
17
                  CommandMenuClose="InsertImageMenuClose"
18
                  Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png" Image16by16Top="-176" Image16by16Left="-224"
19
                  Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="-192" Image32by32Left="-448"
20
                  LabelText="Insert Image"
21
                  MenuAlt="$Resources:core,ButInsertImageMenuAlt;"
22
                  Sequence="10"
23
                  TemplateAlias="o1"
24
                  ToolTipTitle="$Resources:core,cui_ButInsertImage;"
25
                  ToolTipDescription="$Resources:core,cui_STT_ButInsertImage;">
26
            <Menu Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Replacement">
27
              <MenuSection
28
                Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.Replacement"
29
                DisplayMode="Menu"
30
                Sequence="10">
31
                <Controls Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.Controls.Replacement">
32
                  <Button
33
                    Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromComputer.Replacement"
34
                    Sequence="10"
35
                    Alt="$Resources:core,ButFromComputerAlt;"
36
                    Command="UploadPictureReplacement"
37
                    LabelText="$Resources:core,ButFromComputer;"
38
                    ToolTipTitle="$Resources:core,cui_STT_title_ButInsertImageFromComputer;"
39
                    ToolTipDescription="$Resources:core,cui_STT_ButInsertImageFromComputer;"/>
40
                  <Button
41
                    Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromMediaLibrary.Replacement"
42
                    Sequence="15"
43
                    Alt="$Resources:core,ButFromAddressAlt;"
44
                    Command=".MediaLibrary.Ribbon.PerformInsert"
45
                    LabelText="From Media Library"
46
                    ToolTipTitle="Insert Picture from Media Library"
47
                    ToolTipDescription="Insert a picture from Media Library onto the page"/>
48
                  <Button
49
                    Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromAddress.Replacement"
50
                    Sequence="20"
51
                    Alt="$Resources:core,ButFromAddressAlt;"
52
                    Command="InsertImageWeb"
53
                    LabelText="$Resources:core,ButFromAddress;"
54
                    ToolTipTitle="$Resources:core,cui_STT_title_ButInsertImageFromAddress;"
55
                    ToolTipDescription="$Resources:core,cui_STT_ButInsertImageFromAddress;"/>
56
                  <Button
57
                    Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromSharepoint.Replacement"
58
                    Sequence="25"
59
                    Alt="From Sharepoint"
60
                    Command="InsertImageSharepoint"
61
                    LabelText="From Sharepoint"
62
                    ToolTipTitle="Insert Image from Sharepoint"
63
                    ToolTipDescription="Insert an image using the asset picker tool"/>
64
 
65
                </Controls>
66
              </MenuSection>
67
            </Menu>
68
          </SplitButton>
69
        </CommandUIDefinition>
70
      </CommandUIDefinitions>
71
      <CommandUIHandlers>
72
        <CommandUIHandler
73
            Command="UploadPictureReplacement"
74
            CommandAction= "javascript:
75
        var id='?RootFolder=&amp;DisplayType=uploadimages';        
76
        uploadImageDialog(id);
77
        " />
78
 
79
      </CommandUIHandlers>
80
    </CommandUIExtension>
81
 
82
  </CustomAction>
83
</Elements>
84
 
85

Notes:

1) Line 11: The Location specified is exactly the same as the one listed in the CMDUI.xml file (This is the file which lists the OOTB ribbon controls). This is ensures we replace the ribbon control not create a new one.
2) Line 22: Use the same sequence number to replace the button
3) Line 36: The method name which invokes the javascript. See Line 73

Right, so first thing to remember. Everytime you deploy the feature or change it in any way, you need to clear the cookies/cache. Your changes wont be seen otherwise. That took me about 5 hours of work right there!!

Now, for the javascript. We use the ECMAScript opendialog functionality where we specify our own callback function which will be called one we’re done with the upload functionality (not covered here. this functionality would be part of the dialog you launch).

 Javascript |  copy code |? 
01
02
openDialog: function (params) {
03
            params = $.extend({
04
                id: "",
05
                allowMaximize: true,
06
                showClose: true,
07
                callBackFunction: CallDETCustomDialog
08
            }, params);
09
            var siteurl = SP.PageContextInfo.get_webServerRelativeUrl();
10
            var options = SP.UI.$create_DialogOptions();
11
            if (siteurl == "/") {
12
                options.url = params.url + params.id;
13
            }
14
            else {
15
                options.url = siteurl + params.url + params.id;
16
            }
17
            options.allowMaximize = params.allowMaximize;
18
            options.showClose = params.showClose;
19
            options.width = params.width;
20
            options.height = params.height;
21
            options.dialogReturnValueCallback = params.callBackFunction;
22
            SP.UI.ModalDialog.showModalDialog(options);
23
            //SP.UI.ModalDialog.showWaitScreenWithNoClose();
24
        }
25
 
26
// upload Image Dialog
27
function uploadImageDialog(id) {
28
    $(this).openDialog({
29
        id: id,
30
        url: "/_layouts/FileUpload/BasicUpload.aspx",
31
        callBackFunction: InsertImageUploadedCallback
32
    });
33
}
34
 
35
function InsertImageUploadedCallback(dialogResult, returnValue) {
36
 
37
    if (dialogResult == "OK") {
38
        //Delete any existing content the range contains
39
        RTE.Cursor.get_range().deleteContent();
40
 
41
        //Get a handle on the current range of the cursor inside the RTE
42
        var rng = RTE.Cursor.get_range().$3_0;
43
 
44
        //Create a DOM object representing the image
45
        var d = rng.ownerDocument;
46
        var a = d.createElement("img");
47
        //a.setAttribute("id", uniqueid);
48
        a.setAttribute("src", returnValue);
49
 
50
        //Insert the image into the RTE at the current cursor range position  
51
        SP.UI.UIUtility.insertAfter(a, rng);
52
    }
53
    if (dialogResult == "Replace") {
54
 
55
        var $v_0 = RTE.Cursor.getSelectedImage();
56
        if (!$v_0) {
57
 
58
        }
59
        if ($v_0.complete || $v_0.readyState === 'complete') {
60
            $v_0.setAttribute("src", returnValue);
61
        }
62
 
63
    }
64
}
65
 
66

Notes:

1) Line 27: UploadImageDialog launches our dialog with the appropriate callbackfunction
2) Line 21: Is set to InsertImageUploadedCallback
3) Line 37 – Line 51: Use this to insert a new image into the rich text editor.
4) Line 53 – Line 63: Use this to replace the currently selected image

So once we have this functionality we can now create a new aspx page which would be invoked using this dialog. We called ours “basicupload.aspx”.

Within this page’s OnSave method we implemented some javascript which would then invoke the callback method and pass back the image url to the callback method. This is acheived using the following code:

 Javascript |  copy code |? 
1
2
if(containerState == ContainerState.UploadImages)
3
                                        this.Page.ClientScript.RegisterStartupScript(this.GetType(), "InsertImageUploadedCallback", "commonModalDialogClose('OK', '" + oWeb.Url + "/" + oImageItem.File.Url + "');", true);
4
                                    else
5
                                        this.Page.ClientScript.RegisterStartupScript(this.GetType(), "InsertImageUploadedCallback", "commonModalDialogClose('Replace', '" + oWeb.Url + "/" + oImageItem.File.Url + "');", true);                                
6
 
7

Notes:

The code shown above passes back the uploaded image file url back to the callback method based on whether we are replacing or uploading a new image.

Our Sharepoint 2010 Experience

// June 25th, 2010 // No Comments » // Uncategorized

So one of the projects we’re working on is a grand scale education system. It is billed as one of the largest Sharepoint 2010 deployments in the world currently and the budget stretches in the millions. We’re just glad we’ve got to work with cutting edge technology with some of the best sharepoint arhcitects, sharepoint developers and consultants around!

Although i cannot say much about the project it involves building a large LMS system which allows a potential 1.3 million students to collaborate on homework, with teachers and submit assignments online. It has created such a stir in the industry that Steve Ballmer is officially our executive project sponsor! To hear a bit more about it, check out this video. Make sure you fast forward to 23mins into the video to hear about the project!

Sharepoint 2010: Open Modal Dialog from EditControlBlock

// June 9th, 2010 // 3 Comments » // Uncategorized

Visual Studio 2010 makes it really easy to create and upload Features. Using these new Features makes it easy to add actions to menus. One of these menus is the Edit Control Block (ECB) or the context menu which appears over an item:

Edit Control Block

Normally we’d use a simple UrlAction and fill the Url with the redirect. However in this case to call the modal, we can do the following:

 XML |  copy code |? 
01
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
02
  <CustomAction Id="ReportConcern" RegistrationType="ContentType" RegistrationId="0x0101009b56d20860764b8090e63b320d78f98c" Location="EditControlBlock" Sequence="107" Title="Report Concern" Description="To report a concern on this item">
03
    <UrlAction Url="javascript:
04
              function CallDETCustomDialog(dialogResult, returnValue) 
05
              {
06
                SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
07
              }
08
              var options = {              
09
              url: '{SiteUrl}' + '/_layouts/ReportConcern/ReportConcern.aspx?List={ListId}&amp;ID={ItemId}',
10
              title: 'Report Concern',
11
              allowMaximize: false,
12
              showClose: true,
13
              width: 500,
14
              height: 300,
15
              dialogReturnValueCallback: CallDETCustomDialog };
16
              SP.UI.ModalDialog.showModalDialog(options);" />
17
      </CustomAction>
18
</Elements>

Sharepoint and JQuery Web Services: DeleteList

// June 7th, 2010 // 2 Comments » // Uncategorized

I had a requirement today to be able to perform a delete of a list without having to perform a postback. After a little bit of research and a little bit of fine-tuning i came up with a delete list method (deletelist()). Below is just an example of what can be done with the Lists.asmx webservice provided by Sharepoint. Obviously any Web Service can be used or called as required.

 Javascript |  copy code |? 
01
 
02
function delete_list(listid) {
03
            if (confirm("Are you sure you want to delete this container?") == true) {
04
                var message = listid;
05
                var soapEnv =
06
                "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'> \
07
                    <soapenv:Body> \
08
                        <DeleteList xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
09
                        <listName>" + listid + "</listName>\
10
                        </DeleteList> \
11
                    </soapenv:Body> \
12
                </soapenv:Envelope>";
13
 
14
                $.ajax({
15
                    url: "_vti_bin/lists.asmx",
16
                    beforeSend: function (xhr) {
17
                        xhr.setRequestHeader("SOAPAction",
18
        "http://schemas.microsoft.com/sharepoint/soap/DeleteList");
19
                    },
20
                    type: "POST",
21
                    dataType: "xml",
22
                    data: soapEnv,
23
                    contentType: "text/xml; charset=\"utf-8\"",
24
                    complete: processResult,
25
                    success: function (j) {
26
                        document.location.reload();
27
                    }
28
                });
29
 
30
            } else {
31
                return false;
32
            }
33
        }
34
        function processResult(xData, status) { 
35
            var resultXml = $(xData.responseXML).find("errorstring").text();
36
            resultXml = $.trim(resultXml);
37
            if (resultXml != "") {
38
                alert(resultXml);
39
            }           
40
        }
41

Forms Designer for Sharepoint Services

// February 14th, 2010 // 2 Comments » // Uncategorized

Many of our clients operate in the small to medium entreprise (SME) and thus either make the investment into Microsoft Office Sharepoint Server (MOSS) whilst many opt for Windows Sharepoint Services (WSS) as a pilot or proof of concept.

The differential always comes down to a couple of deal breakers:

1) The extent that search will play a role in their organisation
2) The role of the automation of business processes within the organisation

When deciding between MOSS and WSS, for most organisations using Sharepoint 2007 as an intranet, it is normally the deal breakers mentioned above which entice them to go MOSS 2007 or WSS 3.0. When WSS 3.0 was released intially back in 2006, the difference between MOSS 2007 and WSS 3.0 was quite obvious. But as each of the above have been implemented, sharepoint services companies have slowly developed small features to make up the ground between the two. Take Stramit’s Masterpage Picker which gives one the masterpage and branding type functionality of MOSS with a simple feature or Bamboo’s Mashpoint allowing WSS to take advantage of BDC-like functionality. Im not saying that WSS with a couple of codeplex features will replicate the functionality of MOSS, things like Excel Services, Information Management Policies, Search and Navigation. But what am i saying is that WSS can provide a very rich interface for intranet and extranet deployments.

With the advent of Microsoft Search Server Express, search has become extremely powerful in WSS allowing organisations to use WSS to search Sharepoint Content, Website Content, Fileshares and Exhange Public folders (no people search which is at times a real make or break). Nonetheless i feel it still provides a rich functionality which makes me think that Infopath Forms Services is the real deal breaker. How many of you have used Sharepoint Designer to manipulate Sharepoint List Forms? Ever added a new column and then had a look if your customized form inherits the new column? Ever tried to create business rules around a form? For everything that Infopath provides us, i find that we suggest MOSS time and time again purely on the basis of automating business process within a organisation.

Many would disagree with the above, and yes, there are many features which MOSS adds where WSS does not compete, and theres no doubt, given a client has the budget, id suggest MOSS everyday. However id still love to have the “why do you suggest MOSS over WSS” discussion with some of our colleagues at Sharepint, especially to cash strapped SME businesses.

The crux of my post

Infopath has an almost complete set of functionality available to browser-enabled Sharepoint forms. The ability to “import” and “export” data from Line of Business Systems, addition of business rules and branding of Forms makes it the only option to publish forms with rich functionality to Sharepoint. Why is it that Infopath is the only player in the Forms department. There are multiple workflow providers, Nintex and Blackpoint to name a few. They make designing more complex workflows slightly easier to the average business user or sharepoint consultant and certainly have helped our clients save many hours in the solution development lifecycle. With the business process automation market almost captured, why is it that there isnt a forms provider who can compete with the Infopath juggernaut?

It would certainly lead me to recommend WSS to many cash-strapped SME’s depending on the price or licensing model and with the strong built-in workflow capability of WSS, it seems a no-brainer…. or maybe not?