Thursday, August 30, 2007

Running event handlers

Hi!

I was presented with a problem while working at a customer of mine. When running event handlers, specially ItemUpdated, the code might be run several times by different threads. The thing is that the eventhandler makes some changes to the list item that generates an error if the code is run again. That is to say that the name of the item changes in the eventhandler. The problem consists of making sure that the code is only run once.

To solve this problem, I used a hashtable to store a temporary variable. Using a hashtable has the advantage that once the variable is set in the hastable, a try/catch loop will sort out the following threads since the hastable will generate an error if trying to insert duplicates.

Thus, when an error is received from the hashtable, a return statement is set, allowing only the first thread to run the code. Once the code is run, don't forget to reset the hashtable.

Since Gustaf, a colluege of mine, come up with the original idea, here is a link to his blog, also with code examples. http://gustafwesterlund.blogspot.com/2007/08/how-to-stop-infinite-recursionsloops-in.html

//Sebastian

Posted by Zeb at 14:24:47 | Permanent Link | Comments (0) |

Tuesday, August 21, 2007

Dynamically dropdown lists in SharePoint

Hi again!

This article will be about making dynamically dropdown lists in SharePoint. By dynamically dropdown lists I mean that depending on the selected value from one list, the second list is populated with different values.

Most of the code below has been made available by Gustaf Westerlund, an associate of mine. Many thanks!

A customer of mine asked for this feature in an edit form for document properties in SharePoint and the solution was to first create a new custom edit form for the document library of interest, see article about creating a custom form, and then to modify this new edit form so that the desired functionality is obtained.

The prerequisites for this example is that the document library of interest has two columns of type choice and is presented as dropdown lists. The first column has fixed values that can be choosen between and the second dropdown should be depending on the value from the first dropdown.

 When the new form is created and the DataListWebPart has been inserted, a javascript is inserted into the new form to make two dropdownlists dependent on each other. This can only be done after the ListFormWebPart has been removed and the DataListWebPart has been inserted. When the new web part is inserted, the controls are visible for editing in an ordinary table.

The two dropdown lists from the columns mentioned above can now be accessed since the id for the controls can be obtained, either by scrolling though the html-code for the edit form or by running IE Developer Toolbar, downloadable from Microsoft.

Now, I used SharePoint Designer for this part but any editor should be fine, insert a javascript into the edit form. The location of the javascript has some importance and remember that the control that is being called must have been defined before the javascript tag is inserted. I put the script tag just outside the table of the DataListWebPart but still inside the main content asp tag.

<script type="text/javascript">

</script>

The idea now is to populate the second dropdown list with values when the first dropdownlist changes. To do this, a function in the javascript is associated with the onchange event of the first dropdown list. This part of the script is done as shown below.

<script type="text/javascript">                       

var Loader = function()

                             {                               document.getElementById("ctl00_m_g_99ab9b11_70a4_4341_80f3_88f3266dde73_ff11_1_ctl00_DropDownChoice").attachEvent("onchange", ProcessOnChange);

                             }

                             Loader();

</script>

For everyone good at javascript, this is probably a piece of cake, but for many others, including myself, this requires some explanation.

The function Loader only has one row, which finds the control with id ctl00_m_g_99ab9b11_70a4_4341_80f3_88f3266dde73_ff11_1_ctl00_DropDownChoice, which can be found from the form by the methods mentioned above.  The attachEvent method states that on a change of the dropdownlist the function ProcessOnChange should be run. This function is not yet implemented. Once the page is loaded the Loader function is fired, making the onChange event association to the first dropdown list.

The ProcessOnChange we made looking like this;

var ProcessOnChange = function()

                             {

                                                          clearAll();

                                                          populateDropdown ();           

                             }

The functions clearAll is run to make sure that the second dropdown list is empty before new values are populated into the list.

clearAll is defined as below;                        

var clearAll = function()

                             {

                                                          var dropdownlist = document.getElementById("ctl00_m_g_99ab9b11_70a4_4341_80f3_88f3266dde73_ff8_1_ctl00_DropDownChoice");

                                                          var len = dropdownlist.length;

                                                          for (i = 0; i < len; i++)

                                                          {

                                                              dropdownlist.remove(0);

                                                          }

                             }

Here the id for the getElementById is the id for the second dropdown list. It can be obtained by the methods mentioned above.

Lastly, the populateDropdown function is to be defined. This function is separated into three sections for easier understanding. The first part is simply the connection to the two different dropdown lists.

 

var dropdownProcess = document.getElementById("ctl00_m_g_99ab9b11_70a4_4341_80f3_88f3266dde73_ff11_1_ctl00_DropDownChoice");

var dropdownDocumentType = document.getElementById("ctl00_m_g_99ab9b11_70a4_4341_80f3_88f3266dde73_ff8_1_ctl00_DropDownChoice");

 

The second part is the definition of different variables in order to more efficiently populate the second dropdown list. Here only three options are defined, but many more options can be made available for inserting into the dropdown list.

 

var documentTypeAuditPlan = document.createElement('option');

documentTypeAuditPlan.text = "Audit Plan";

var documentTypeAuditReport = document.createElement('option');

documentTypeAuditReport.text = "Audit Report";                                          

var documentTypeAuditActionPlan = document.createElement('option');

documentTypeAuditActionPlan.text = "Audit Action Plan";                                                       

 

The dropdown list requires variables defined as above.

The last part of the function is a case statement, in this case a switch is used. In order to get the switch to work, the evaluated statement must be placed in a variable.

var selectedProcess = dropdownProcess.options[dropdownProcess.selectedIndex].text;                                         

switch(selectedProcess)

{

case "Management Process":

dropdownDocumentType.add(documentTypeAuditPlan);                                                                                       dropdownDocumentType.add(documentTypeAuditReport);                                                    dropdownDocumentType.add(documentTypeAuditActionPlan);                                           

break;               

default:

}

 

This switch will look at the text of the selected value from the first dropdown list and if the text is Management Process, which is one of the choices for that column to which the dropdown list is linked, the second dropdown list will be populated with the values Audit Plan, Audit Report and Audit Action Plan.

Now, the values that the second dropdown list is being populated with must also exist in the choice list linked to the dropdown list. Otherwise if a value that is not in the choice list is being selected, SharePoint will return an error.

I'm not a big fan of JavaScript because of several reasons and everyone taking this article as a guideline should be aware of that it is quite tricky to get the JavaScript to function properly. Agood way of trying your scripts before making them part of the edit form is to go to w3schools and try their try-it Editor. Just paste your code and click the button to see if it works.

Another thing that might help is to try the code step by step and write in a couple of alerts(string s), as a simple debugger, that will pop up a string in a dialog box when it is run.

Good luck!

//Sebastian

Posted by Zeb at 19:42:41 | Permanent Link | Comments (5) |

Custom Forms in SharePoint 2007

Hi!

This post will be about creating a custom form for a list. The need to do this arose when a customer of mine wanted a pair of dynamic dropdown lists where this was the first step in the solution.

This information has been taken from SharePointExpert and from Kristian Kalsing's blogpost about custom forms which are both excellent blogs with many good articles.

First off, open SharePoint Designer (SPD) and open the web site of interest.

Next, navigate to the list which is to have the custom form and find the folder Forms inside the list. Inside this folder resides all the default forms that the library will use for any given situation such as uploading, checking in or editing the properties of a document.

Now, open the form that you whish to make a customized version of. Notice that the form only contains a single webpart, the ListFormWebPart.

This webpart does not allow us to do anything useful and therefore we are going to remove it. But before you do this, make a copy of the form you opened and give it a good name. In my case, with my customer, it was the EditForm.aspx that was copied to EditForm2.aspx.

When the ListFormWebPart has been removed, a new control is going to be inserted. Goto Insert -> SharePoint Control -> Custom List Form. This will bring up a dialog box where the list, content type and operation type can be selected. Once you have selected all of these, click the Ok button.

As can be seen, I have chosen to make a new Edit form for my Shared Document which uses the Document content type. Now, all metadata fields will appear in a table which you can edit and modify as you whish. Be careful when removing fields that you don't want the users to see so that the fields are not required.

When you are done, go to a browser and navigate to the list that has the customized form and try it out. This can be done in many ways, the easiest that I have found is to go to the original form and then write in your name instead of the original form name in the adress field.

After this comes the tricky part, getting the form to actually appear as the default form for the operation.

To be able to do this go to the list in SharePoint Designer and right click. Choose Properties and then go to the tab named Supporting Files. Here you will be able to upload different forms than the default SharePoint forms, such as the form you have just created.

Upload you new form. This is not end of it though. When hitting the Ok button the error "the page you have selected does not contain a reference to the correct sharepoint list..." will appear. To get rid of this error you have to go back to the original form and copy the whole WebPartZone tag with all its content to the new form. This will give you two web part zones in your form and both have the same Id. Rename your webpart zone with the DataListWebPart to something else.

Now go down into the ListFormWebPart, that is the web part you just copied into your customized form, and set the IsVisible tag to false.

Now the new form will be the default form for the specified action.

Good luck!

 

//Sebastian

Posted by Zeb at 17:27:06 | Permanent Link | Comments (9) |