Back from the Dead

I am back, sort of. I came back a couple of weeks ago but the company has me working hard on some documentation. I do all of the documentation in a program called MadCap Flare. I just dusted off and launched SharePoint Designer for the first time in over a month today…

Give me a couple of days to get everything back into place in my brain (I was looking at some notes to try to figure out where I left off and I am totally lost). I am going to be pushing hard on the sales management section of my web application over the next month or so.

I really missed blogging and I realised that my documentation role is taking more and more time from SharePoint Design (and therefore SharePoint Blogging). To that end, I’ve created another blog about personal finances and budgets, my second favorite personal torture.

If you are into that kind of stuff, I should have some posts up at the site very soon (http://splittingcents.wordpress.com). As for this blog, I think I might attack creating some examples and screenshots for the new posts so be prepared for some new stuff from me!

Add comment September 24, 2008

Update: AWOL

Sorry, I haven’t had the responsibility of being a blogger before. I never even realised that if I drop off the face of the web for a while, people keep reading my stuff ;)

I was away for a while, I am sort of back. I have a big family wedding coming up next week and I am the impromptu planner now. Needless to say, I am completely lost. I have approved the recent comments and will post replies to them, most likely tomorrrow.

Sorry for not posting that I would be gone. Good luck with your designs!!

Add comment August 18, 2008

Use Javascript Redirects to hide SharePoint default sites

I’ve been working diligently on the new web application and I needed to record this little tip. I am creating new forms for entering items and viewing of lists, but users can still get to the default SharePoint pages through areas I haven’t customised – the search results is currently the easiest – but also the bread crumb trail on some pages.

To get around this, I am using the Javascript redirect and placing it in the <head> section of the default SharePoint pages for my lists – so even if I miss a link somewhere – the user never sees the SharePoint page. They are automaticaly redirected to the custom form I spent hours designing. After all, they really do need to see my spectacular work don’t they?

I started by creating a Content Place Holder in the master page so it would be available to all pages – I find this useful for inserting ANY Javascript and not just for this tip. Just before the closing </head> tag in the master page, I added the following line to create the place holder:

<asp:ContentPlaceHolder id=”PlaceHolderAdditionalPageHead” runat=”server”/>

Now, this is probably pretty basic to some of you, but others might not know how to add these to the master page. Any code on a SharePoint page that contains content place holders, must be in a content place holder - so don’t just try to slap the Javascript on the aspx page.

On the aspx page, for example dispform.aspx, I inserted the following code – just after the declarations at the top of the page - I want it to be the first thing that loads on the page:

<asp:Content ContentPlaceHolderID=”PlaceHolderAdditionalPageHead” runat=”server”>
 <script type=”text/javascript”><!–
location.href = ‘http://sharepointsite/sites/webapplication/Lists/List name/customform.aspx’;
// –></script> 
</asp:Content>

As you can see from the code, the Javascript just changes the location.href for the page to a new address and the user is instantly redirected. Hope this helps to hide any nasty SharePoint pages that jump in and ruin your nice designs.

Thanks for Reading

4 comments July 18, 2008

Site Theme Change

I had to change the site theme because it was cutting off items I was posting. I apologise in advance, hopefully it won’t become a regular issue (I personally hate it when sites suddenly change- aaaagh).

Thanks for understanding…

Add comment June 27, 2008

CSS Table Cell Borders

Just a quick post to store a line of code I need, but others may find helpful. I have some Multiple Item Views that are styled using CSS to have a border. The problem is, if there is no value in the field, the table cell doesn’t get created so the borders don’t exist. This issue has existed in HTML for ages and it could be easily remedied by placing a ’space’ in the cell as a default value. The code for space in HTML is “&nbsp;” (without the quotes). But in a SharePoint dataview you have to do something slightly different:

SharePoint Dataview table cells can be padded with this line of code:

 <xsl:text xmlns:ddwrt=”http://schemas.microsoft.com/WebParts/v2/DataView/runtime” ddwrt:nbsp-preserve=”yes” disable-output-escaping=”yes”>&amp;nbsp;</xsl:text>

You would add the code within the <td> brackets of the table cell. For example:

<td width=”75%” class=”ms-vb”>
       <xsl:value-of select=”@JobTitle” />
 </td>

Would be changed to:

<td width=”75%” class=”ms-vb”>
       <xsl:value-of select=”@JobTitle” /> <xsl:text xmlns:ddwrt=”http://schemas.microsoft.com/WebParts/v2/DataView/runtime” ddwrt:nbsp-preserve=”yes” disable-output-escaping=”yes”>&amp;nbsp;</xsl:text>
</td>

Now if the table cell contains no value, it will still contain a space and therefor the table cell will still render in the HTML when the page is displayed. Just be aware that when a user copies and pastes out of the cell, there will be an additional space tacked on to the end of the selection.

Hope that helps

1 comment June 27, 2008

Web Application Design (part 2)

I was on a roll today so I thought that I might as well get part 2 going.

In part 1, I covered the steps for creating and customising the display and edit forms for a custom list on a single aspx page. I now want to combine the new item form for the custom list on the same aspx page and give the user a button to show the new item form and hide the edit form.

Step One: Add the New Item Form

We need to add the Data View Web Part for a New Item Form after the edit form.

  1. Locate the end tag for the edit form: </WebPartPages:DataFormWebPart>.
  2. Add a <br /> tag immediately after the close tag.
  3. Insert a Data View.
  4. Select the Customer Status list from the Datasource Library.
  5. Hold CTRL and select the fields you want to add.
  6. Click on the Insert Selected Fields As button and select New Item Form.

SharePoint will insert the new item form on the page. The forms on the page are now fully functional and the user can edit items in the grid and add items to the grid from the same page. However, the usability for this page is very poor. The user can select an item in the display grid and then enter the changes in the new form thinking they are editing the existing item (like an old password/new password screen) and when they save they accidently create a new record. There are other usability issues as well, but we can address them all by hiding the edit form when the new form is in use.

Step Two: Create Containers for the Forms

We have two forms on our screen that need to be identified from each other: the edit form and the new form. Those two forms also need to be hidden or shown depending on the situation. To accomplish this, I place each of the Web Parts with in a DIV.

  1. Locate the start tag for the edit form: <WebPartPages:DataFormWebPart ….
  2. Insert the following code BEFORE the start tag: <div id=”EditForm” style=”display: block”>
  3. Locate the end tag for the edit form: </WebPartPages:DataFormWebPart>
  4. Add the following code AFTER the end tag: </div><!–close div#EditForm–>

With these four simple steps, I have created a container around the web part. Now we need to create the container around the new form. I have highlighted the subtle differences:

  1. Locate the start tag for the new form: <WebPartPages:DataFormWebPart ….
  2. Insert the following code BEFORE the start tag: <div id=”NewForm” style=”display: none”>
  3. Locate the end tag for the new form: </WebPartPages:DataFormWebPart>
  4. Add the following code AFTER the end tag: </div><!–close div#NewForm–>

Note: Once you set the display attribut to “none”, you will no longer be able to see the form in design view. If you need to make changes, you can edit the form in code view or temporarily change the display value to “block”.

Sidebar: Naming Items
You should always give your items unique ids or names on a web page, especially when we use JavaScript or CSS. Properly identified items are easy to locate and manipulate in the code. If I have 30 tables on a screen, it can take forever to locate a specific one. If I name the tables, I can do a CTRL+F to locate the name quickly and efficiently. You can also apply CSS styles directly to named items.
The DIV tag is used to denote a “division” on the page. In normal web page design, I would place the banner in one div, the body in a separate div, and the footer in another div. I can refer to the sections of the document for formatting and style by their div (container). For example the following CSS: 

div#footer a {text-decoration:none;}

The CSS would style ANY <a> tag withing the Footer div as having no underline. Any <a> tags in the body or other div would not be affected.

Sidebar: Nested Divs
Step 4 contains an HTML comment tag <!–your text here–>. The HTML comment is ignored by the browser so that user’s cannot see it, but it helps to identify the tag you are working with. When you start to make complicated web pages, you will notice that you end up with nested divs, one div inside of another div, and at the end of your site you will see code like this:

           </div>
        </div>
    </div>

Unfortunately, you won’t know which div belongs to which starting tag. I always label my closing divs so they look like this:

       </div><!–close div#banner–>
   </div><!–close div#navbar–>
</div><!–close div#header–>

Back to the example… 

Step Three: Create A New Button

IMPORTANT: Make a backup copy of your page before proceeding with this next step. Sometimes when I add the extra row to the table, it causes the Web Part Connection to stop working.

Now that we have the forms inside of their own identifiable containers, we need a button for the user to click to trigger the JavaScript code.

  1. Right-click in the top row of the display form and select Insert > New Row Above.
  2. Select all of the cells in the new empty row and right-click and select Modify > Merge Cells.
  3. Switch to code view and locate the <td> tags for the row (only one column now).
  4. Add the following code in between the <td> tags: <input class=”tbb” id=”tbb” type=”button” value=”New”/>

The class and id attributes in the <input /> tag are optional; I use the class and id attributes in the <input /> tag to identify the button for my styling (tbb stands for tool bar button). We now have a nice shiny “New” button at the top of our display form.

Step Four: Make that Button Work

The New button we created in Step Three doesn’t really do anything, so let’s give it some power. 

  1. Locate the <input /> tag.
  2. Change code to look like this: <input class=”tbb” id=”tbb” type=”button” value=”New”  onclick=”document.getElementById(’EditExistingCodeForm’).style.display =’none’;document.getElementById(’AddNewCodeForm’).style.display =’block’;”/> 

Okay, I know, I kind of surprised you with that one. Let’s break the code down to see what it does:

<input class=”tbb” id=”tbb” type=”button” value=”New” 

There is nothing scary here, we’re telling the HTML to create a button and label it “New”.

onclick=”document.getElementById(’EditForm’).style.display =’none’; document.getElementById(’NewForm’).style.display =’block’; “/>

When the button is clicked, the EditForm div’s display attribute is set to “none” and the NewForm div’s display attribute is set to “block”. In other words, the edit form disappears and the new form appears. You now have a New button that, when clicked, hides the edit form and shows the new form so the user can enter new items into the list.

Step Five: Set the Focus

I found one issue with the current set up; when the user clicks the New button the focus remains on the button and the user has to move the mouse down to the form. Since we are designing with usability in mind, this is a definite no-no.

The code for setting the focus using JavaScript is:

 document.FORMNAME.ID.focus();”

First, we need to identify the name of the form. You can look around for it if you want but, I can save you some time and tell you that SharePoint creates one form for the whole page. The form is called “aspnetForm”.

Secondly, we need to identify the field in the new form. If you click on the field in SharePoint Designer, and look at the code, you will see the following:

<SharePoint:FormField runat=”server” id=”ff1{$Pos}” ControlMode=”New” FieldName=”Title” __designer:bind=”{ddwrt:DataBind(’i',concat(’ff1′,$Pos),’Value’,'ValueChanged’,'ID’,ddwrt:EscapeDelims(string(@ID)),’@Title’)}” />

The only part of that code we are interested in is the id attribute (see how it get’s easier to understand the code behind the site?). The only problem is that the id attribute contains a SharePoint variable. The value in the variable isn’t defined until the server runs the page. So, I viewed the source of the page in the browser and located the same line of code:

<input name=”ctl00$mainContent$g_0e261cef_df83_4297_aa14_312ac818785e$ff1_new$ctl00$ctl00$TextField” type=”text” maxlength=”255″ id=”ctl00_mainContent_g_0e261cef_df83_4297_aa14_312ac818785e_ff1_new_ctl00_ctl00_TextField” title=”Counter” class=”ms-long” />

If you are trying to locate this in the source of your page, follow these steps:

  1. Preview the page in a browser.
  2. View the source (in IE, right-click on the page an select View Source).
  3. Press CTRL+F and search for the label. In our example, the label for the first field is called ”Status:”, so I searched for that.
  4. The label will be contained with <td> tags. The next entry after the </td> tag will be field we are looking for. Since it is an text input box, the tag will be <input> and it will have an attribute of type=”text”. 

If you compare the code in SharePoint Designer with the code from the browser, you can see that the SharePoint code has been ‘run’ on the server and the result is the HTML tag for the field. We are interested in the id attribute only;

id=”ctl00_mainContent_g_0e261cef_df83_4297_aa14_312ac818785e_ff1_new_ctl00_ctl00_TextField”

That is the id of the field we want to set the focus on. So now let’s combine the formname and the id for the field and write the JavaScript:

 document.aspnetForm.ctl00_mainContent_g_0e261cef_df83_4297_aa14_312ac818785e_ff1_new_ctl00_ctl00_TextField.focus();

Now we need to add it to our New button:

<input class=”tbb” id=”tbb” type=”button” value=”New”  onclick=”document.getElementById(’EditExistingCodeForm’).style.display =’none’;document.getElementById(’AddNewCodeForm’).style.display =’block’; document.aspnetForm.ctl00_mainContent_g_0e261cef_df83_4297_aa14_312ac818785e_ff1_new_ctl00_ctl00_TextField.focus();”/>

You now have a New button that, when clicked, will hide the edit form, show the new form and set the focus to the first field. As you may have already guessed, being able to set the focus to a specific field is a valuable tool when designing your own web applications.

This concludes part 2 of my Web Application. The next step will be to create additional functionality for the page – adding a delete button, print button, anything else I can come up with to make the page more user friendly.

Add comment June 11, 2008

Web Application Design (part 1)

Sorry I’ve been away from posting for so long. I’ve been working on a large web application and the design and implementation is taking up a lot of my ‘blogging’ time. But, I use this blog as my notes to remind me how I did certain things, so I need to update it with some new tricks before I completely forget them…

I’ve been adding JavaScript into my projects for a while now, and I’ve started to get a good feel for what I can and can’t do in SharePoint. The following series of tips are very basic and can be accomplished by novice SharePoint designers with ease. If you have any questions, or suggestions to improve my rudimentary code, feel free to post a comment so everyone can learn from the discussions.

The application I am designing requires users to create ‘codes’ for use in drop-down lists. The codes are stored in a custom list which contains only two columns: Code Name (Title) and Active (checkbox). For this series of posts we are going to create a simple list of Customer Statuses. The web application stores Customer Data and the status field in the Customer Data is a lookup to the values in the Customer Status list. The users can therefore add or change codes the drop-down without having to fiddle with SharePoint. The logic used in these examples can be applied to almost any kind of custom list: employee lists, inventory lists, issue tracking lists etc.

I want one page where the user can see the current items in a list, edit the existing items, and create new items in the list. I realise that this can be accomplished by using the DispForm.aspx, NewForm.aspx, and EditForm.aspx but, I want to maintain only one form.

Note: I have started using my own custom masterpage and designing my aspx pages from scratch. I don’t know if these instructions will be affected by placing the forms in an existing SharePoint page, for example – adding a display list to the NewForm.aspx page. I don’t think that it will, but please let me know if it does.

Step One: Display the current contents of the list

Pre-requisite: Create a custom list and populate it with a couple of items.

The primary objective of the page I am creating is to show users the current items in the list, in our example I want to show the users which Customer Status codes already exist in the list. Let’s start by creating a Multiple Item Data View Web Part and place it on the page. I’m pretty sure I’ve covered this in a previous topic but here’s quick recap:

  1. Click anywhere on the page, outside of any existing Web Parts, and insert a Data View.
  2. Click on the Data View and then select the Customer Status list from the datasource library and then click Show Data.
  3. Hold CTRL and select the fields you want to add.
  4. Click on the Insert Selected Fields As button and select Multiple Item View.

The grid (table) will appear on the page and display the contents of the list.

Step Two: Add a an Edit Form

We want the users to be able to click on an item in the grid and be able to edit the item on the same page. Let’s add a Single Item Form Data View.

  1. Locate the end tag for the previous Web Part: </WebPartPages:DataFormWebPart>
  2. Insert a <br /> (to create some space) after the end tag.
  3. Insert a Data View after the <br /> tag.
  4. Click on the Data View and then select the Customer Status list from the datasource library and then click Show Data
  5. Hold CTRL and select the fields the user can edit
  6. Click on the Insert Selected Fields As button and select Single Item Form.

The new form will appear on the page and show the first item in the Customer Status list.

Step Three: Connect the Forms

If you recall, from the previous step, we want the user to be able to click an item in the first grid and have that set the item that can be edited in the edit form. We are going to create a Web Part Connection.

  1.  Right-click a label field, in the edit form we created in Step Two, and select Web Part Connections from the pop-up menu.
  2. When the Web Part Connections Wizard dialog box opens, select Get Parameters From in the drop-down list and click Next.
  3. Verify the radio button for Connect to Web Part on this Page is selected and click Next.
  4. Verify the target Web Part is Customer Status and the target action is Send Row of Data To and click Next.
  5. Click on the Create New Parameter option in the Inputs to Customer Status column.
  6. Name the new parameter “PassedID” and click OK.
  7. Select the ID column from the Columns in Customer Status column in the same row as the PassedID parameter. You are associating the ID column in the display grid with the PassedID parameter in the edit form.
  8. Click Next.
  9. Verify that the Create a Hyperlink On option is set to the Status column.
  10. Select the Indicate Current Selection Using checkbox and select Status from the pop-up list.
  11. Click Next.
  12. Click Finish.

IMPORTANT: I have found a possible bug in SharePoint Designer. In my installation (could just be me), when I have completed the creation of the Web Part Connection sometimes the connection is still not “active”. You can verify the connection was created properly by right-clicking a field in the edit form and selecting Web Part Connections from the pop-up. If the connection was created properly, it will appear in a list. If it was not created properly, the web part connection wizard will launch again. I sometimes find that I have to run the wizard twice (just clicking Next all the way through it the second time) to get the connection to “activate”.

Now that you have the connection established, we need to create a filter on the edit form.

  1. Select the edit form and select Dataview > Filter from the file menu.
  2. Create a filter: ID equals [PassedID]
  3. Click OK

Okay, we now have a grid that shows all of the items in the Customer Status List and if the user clicks on the Status it can be edited in the edit form just below the grid. SharePoint creates a hyperlink on the Status field and highlights the currently selected field.

Step Four: Hyperlink on the Row not the Column

In our current example, the user has to click the Status to change the current item in the edit form. I want to change it so the user can click anywhere in the row and update the edit form. Here is where things get a little scary for beginners. I’m going to try to explain this as clearly as possible because learning this trick is important to gaining control over SharePoint pages.

SharePoint uses HTML tables to structure the layout of the forms and pages. HTML tables always follow the same pattern:

  • The table always begins with the <table> tag and ends with the </table> tag.
  • Each row in the table starts with <tr> and ends with a </tr>. The term ”tr” stands for table row.
  • Each column in a row starts with a <td> and ends with a </td>. The term “td” stands for table data cell (I know it’s not very intuitive!!).
  • SharePoint uses XSL to create the table dynamically. SharePoint specifies the value of the first row and the XSL creates as many rows as needed to contain all of the data.

Once we understand these four truths, we can begin to control the way SharePoint behaves (Don’t worry if they seem confusing right now, once we delve into the code it will start to make more sense). If you set the view in SharePoint Designer to SPLIT the screen, you can see the code and the design at the same time. Click on the first Status field in the display form and you can see the code that creates the field. In our example, SharePoint has placed the hyperlink tag <a> inside of the column <td> tag, here’s the code directly from SharePoint (with my comments in red italics):

<tr> (create a row in the table – we’re going to need this tag very soon)
   <xsl:if test=”position() mod 2 = 1″> (everything between the XSL tags is programming stuff)
    <xsl:attribute name=”class”>ms-alternating</xsl:attribute>
   </xsl:if>
   <xsl:if test=”$dvt_1_automode = ‘1′” ddwrt:cf_ignore=”1″>
    <td class=”ms-vb” width=”1%” nowrap=”nowrap”>
     <span ddwrt:amkeyfield=”ID” ddwrt:amkeyvalue=”ddwrt:EscapeDelims(string(@ID))” ddwrt:ammode=”view”></span>
    </td>
   </xsl:if>(end programming stuff)
   <td class=”ms-vb”> (this is the first column the user can see – in our case the Status column)
    <a target=”_self”> (this is the hyperlink we are looking for)
    <xsl:attribute xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” name=”href”>
     <xsl:variable name=”cursel”>dvt_curselkey={
      <xsl:call-template name=”dvt.gencurselkey”>
       <xsl:with-param name=”RowPath” select=”.” />
      </xsl:call-template>
      }</xsl:variable>
     <xsl:variable xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” name=”fields”>@ID=<xsl:value-of select=”ddwrt:ConnEncode(string(@ID))” /></xsl:variable>
     <xsl:text>javascript:</xsl:text>
     <xsl:value-of select=”ddwrt:GenFireConnection(concat(’g_fed65d2c_6c05_48ed_b84a_0ddc96bdc324*’,$fields),string($cursel))”></xsl:value-of>
    </xsl:attribute>
    <xsl:attribute name=”style”>
     <xsl:if test=”$CurrentRowKey = $dvt_curselkey”>font-weight: bold;</xsl:if>
    </xsl:attribute>
    <xsl:value-of select=”@Title” />
    </a> (this is the end of the hyperlink tag) </td> (this is the end of the column)
   <td class=”ms-vb”>
    <xsl:choose>
     <xsl:when test=”@Active=’1′ or msxsl:string-compare(string(@Active),’Yes’,”,’i')=0 or msxsl:string-compare(string(@Active),’True’,”,’i')=0″>Yes</xsl:when>
     <xsl:otherwise>No</xsl:otherwise>
    </xsl:choose>
   </td>
   </tr> (this is the end of the row)

I want to break the hyperlink code down a little more for you. Here is the contents of the <a> (hyperlink) tag explained in more detail:

<a target=”_self”> (start the hyperlink, but when clicked just reload the current page: target = self)

(This section contains the Web Part Connection Code – very simply put, when I get clicked send the value of the ID field in the current row to the edit form)
<xsl:attribute xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” name=”href”>
     <xsl:variable name=”cursel”>dvt_curselkey={
      <xsl:call-template name=”dvt.gencurselkey”>
       <xsl:with-param name=”RowPath” select=”.” />
      </xsl:call-template>
      }</xsl:variable>
     <xsl:variable xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” name=”fields”>@ID=<xsl:value-of select=”ddwrt:ConnEncode(string(@ID))” /></xsl:variable>
     <xsl:text>javascript:</xsl:text>
     <xsl:value-of select=”ddwrt:GenFireConnection(concat(’g_fed65d2c_6c05_48ed_b84a_0ddc96bdc324*’,$fields),string($cursel))”></xsl:value-of>
    </xsl:attribute>

(This section contains the highlight code – set the currently clicked item to bold font)
    <xsl:attribute name=”style”>
     <xsl:if test=”$CurrentRowKey = $dvt_curselkey”>font-weight: bold;</xsl:if>
    </xsl:attribute>

(This is the data field to display)
    <xsl:value-of select=”@Title” />

    </a>(end the hyperlink)

I hope all of that “random” code makes a little more sense now. By recognising the basic tags in the code, we can locate and manipulate individual columns and rows. We wanted to move the <a> tag so that the hyperlink affects the whole row in the grid. The next section of code shows you the altered code and I will highlight what I moved:

<tr>
<a target=”_self”>
    <xsl:attribute xmlns:xsl=”
http://www.w3.org/1999/XSL/Transform” name=”href”>
     <xsl:variable name=”cursel”>dvt_curselkey={
      <xsl:call-template name=”dvt.gencurselkey”>
       <xsl:with-param name=”RowPath” select=”.” />
      </xsl:call-template>
      }</xsl:variable>
     <xsl:variable xmlns:xsl=”
http://www.w3.org/1999/XSL/Transform” name=”fields”>@ID=<xsl:value-of select=”ddwrt:ConnEncode(string(@ID))” /></xsl:variable>
     <xsl:text>javascript:</xsl:text>
     <xsl:value-of select=”ddwrt:GenFireConnection(concat(’g_fed65d2c_6c05_48ed_b84a_0ddc96bdc324*’,$fields),string($cursel))”></xsl:value-of>
    </xsl:attribute>

   <xsl:if test=”position() mod 2 = 1″>
    <xsl:attribute name=”class”>ms-alternating</xsl:attribute>
   </xsl:if>
   <xsl:if test=”$dvt_1_automode = ‘1′” ddwrt:cf_ignore=”1″>
    <td class=”ms-vb” width=”1%” nowrap=”nowrap”>
     <span ddwrt:amkeyfield=”ID” ddwrt:amkeyvalue=”ddwrt:EscapeDelims(string(@ID))” ddwrt:ammode=”view”></span>
    </td>
   </xsl:if>
   <td class=”ms-vb”>
        <xsl:attribute name=”style”> (we didnt need to move the style code)
     <xsl:if test=”$CurrentRowKey = $dvt_curselkey”>font-weight: bold;</xsl:if>
    </xsl:attribute>
    <xsl:value-of select=”@Title” />
    </td>
   <td class=”ms-vb”>
    <xsl:choose>
     <xsl:when test=”@Active=’1′ or msxsl:string-compare(string(@Active),’Yes’,”,’i')=0 or msxsl:string-compare(string(@Active),’True’,”,’i')=0″>Yes</xsl:when>
     <xsl:otherwise>No</xsl:otherwise>
    </xsl:choose>
   </td>
   <td class=”ms-vb”>
    <xsl:value-of select=”ddwrt:FormatDate(string(@Created), 1033, 5)”/>
   </td>
   <td class=”ms-vb”>
    <xsl:value-of select=”@Author” disable-output-escaping=”yes”/>
   </td></a> (the location of this tag is very important – before the </tr> but AFTER the </td> )
  </tr>
 
As you can see in the example code, I have moved the <a> tag from the inside of the column ( <td> ) to the inside of the row ( <tr> ). If I save and preview this page, I can now click anywhere in the row to change the value in the edit form.

Note: the mouse pointer doesn’t change to reflect the row is a hyperlink but we will correct that in the next step.

Step Five: Change Mouse Pointer on Hover

Changing the mouse pointer when over an item is a very useful JavaScript tip. Users recognise links on a web page from the underline or from the mouse pointer changing when over the link.

If you recall the code I showed you in Step Four, I noted that we would need the <tr> tag. Locate the <tr> tag (the easiest way is to switch to split view and click the first row in the display form). Add the following code to the <tr> tag:

<tr onmouseover=”this.style.cursor=’hand’”>

All I’ve done here is tell the browser to initiate the JavaScript on the row. The JavaScript (onmouseover) activates when the mouse pointer is over the item, in this case the row. The values in the quotes tell the JavaScript to change the cursor (mouse pointer) to the hand. Insert the code in your page and preview the page. When you move the mouse over a row in the display form, it will change to a ‘hand’ cursor and your user knows that they can click there.

As you might have already guessed, you can use this little trick in a lot of other situations.

Step Six: Add Some Usability

When I look at the forms we have just created I’m happy with the functionality but, I am not so impressed with the usability. If the list contains 200 items, how do you expect the user to see the little bold highlight on the currently selected row? I want to add some custom code to the forms to improve the usability.

Highlight the Row

There are two types of highlight that I like to use when displaying a grid full of data. If the grid has the edit form on the same page, I want the currently selected row to be highlighted. If the grid links to an edit form on a different page, I want the row to highlight when the mouse pointer moves over it.

In our example, the edit form is on the same page so I want the row to highlight when the user clicks it. If you were paying attention in Step Four, you might have seen that this functionality already exists in a slightly modified format:

    <xsl:attribute name=”style”>
     <xsl:if test=”$CurrentRowKey = $dvt_curselkey”>font-weight: bold;</xsl:if>
    </xsl:attribute>

The XSL code sets the style on the column when it is the currently selected item. As is, it gives the Status field a tiny little bold affect. Let’s tinker with the code a little:

    <xsl:attribute name=”style”>
     <xsl:if test=”$CurrentRowKey = $dvt_curselkey”>background-color: #ffffe0;</xsl:if>
    </xsl:attribute>

As you can see, I only changed the style value in the XSL code. The code now sets the background of the selected column to be a nice pale yellow color. You can specify any color you want and you can also change almost any style you want. Here are some examples:

   border: 1px solid red; (set the border of the selected column to red)
   text-decoration: underline; (underline the text in the selected column)

You should experiment with the different combinations of CSS style attributes and values. If you tested and previewed the change, you are probably wondering why only one column is affected. The code for the style is contained with the <td> tag so it affect only the single column. If you copy and paste the style code into each of the columns – it will affect all of the columns. You can’t move the style code up to the row without messing up the web part connection – so for now you have to copy and paste it. Here is the sample code:

<tr>
<a target=”_self”>
    <xsl:attribute xmlns:xsl=”
http://www.w3.org/1999/XSL/Transform” name=”href”>
     <xsl:variable name=”cursel”>dvt_curselkey={
      <xsl:call-template name=”dvt.gencurselkey”>
       <xsl:with-param name=”RowPath” select=”.” />
      </xsl:call-template>
      }</xsl:variable>
     <xsl:variable xmlns:xsl=”
http://www.w3.org/1999/XSL/Transform” name=”fields”>@ID=<xsl:value-of select=”ddwrt:ConnEncode(string(@ID))” /></xsl:variable>
     <xsl:text>javascript:</xsl:text>
     <xsl:value-of select=”ddwrt:GenFireConnection(concat(’g_fed65d2c_6c05_48ed_b84a_0ddc96bdc324*’,$fields),string($cursel))”></xsl:value-of>
    </xsl:attribute>

   <xsl:if test=”position() mod 2 = 1″>
    <xsl:attribute name=”class”>ms-alternating</xsl:attribute>
   </xsl:if>
   <xsl:if test=”$dvt_1_automode = ‘1′” ddwrt:cf_ignore=”1″>
    <td class=”ms-vb” width=”1%” nowrap=”nowrap”>
     <span ddwrt:amkeyfield=”ID” ddwrt:amkeyvalue=”ddwrt:EscapeDelims(string(@ID))” ddwrt:ammode=”view”></span>
    </td>
   </xsl:if>
   <td class=”ms-vb”>
    <xsl:attribute name=”style”>
     <xsl:if test=”$CurrentRowKey = $dvt_curselkey”>background-color: #ffffe0;</xsl:if>
    </xsl:attribute>
    <xsl:value-of select=”@Title” />
    </td>
   <td class=”ms-vb”>
   <xsl:attribute name=”style”>
     <xsl:if test=”$CurrentRowKey = $dvt_curselkey”>background-color: #ffffe0;</xsl:if>
    </xsl:attribute>

    <xsl:choose>
     <xsl:when test=”@Active=’1′ or msxsl:string-compare(string(@Active),’Yes’,”,’i')=0 or msxsl:string-compare(string(@Active),’True’,”,’i')=0″>Yes</xsl:when>
     <xsl:otherwise>No</xsl:otherwise>
    </xsl:choose>
   </td></a></tr>

In our example, we only have two columns showing. If you have multiple columns, all you need to do is locate the starting tag for each column: <td class=”ms-vb”> and place the style code snippet directly after it.

To sum up, we now have a single aspx page that contains a grid displaying of all of the items in a custom list with an edit form directly below the grid. The user can click anywhere in a row in the grid and the selected row is highlighted and the edit form updates to show the selected item. The user can then edit the item in the edit form and click save and see the changes in the display grid.

In the next part, I will add a New button to the page which will hide the edit form and show a new item form which will allow users to add new items to the display grid from the same aspx page.

9 comments June 11, 2008

Logging Workflows for Troubleshooting

SharePoint workflows are very powerful tools. SharePoint workflows allow you to automate tasks and workflow processes. If you haven’t used workflows before, I recommend reading the SharePoint online help for workflows:

http://office.microsoft.com/en-us/sharepointdesigner/CH100667661033.aspx

Once you start to use workflows in your SharePoint applications, you realise a very important and fundamental truth; what happens when a workflow fails? By default, you can click on an item in a list and see the workflow history. Unfortunately, the error messages in the workflow can be cryptic to say the least. For example, if I have a workflow that creates new items in 5 different lists and the workflow fails, I get a message saying “Unable to update list item”. The message doesn’t tell me which specific action or step failed or which list it was unable to write to.

To get around this issue, and to provide an even finer level of control over my workflows, I created a custom list and used that list to log my workflow actions. The custom list, called WorkflowLog, contains the following fields:

  • Workflow Name (text field) – stores the name of the workflow that is logging the event.
  • EventOccurred (date & time field) – stores the date and time that the event was completed.
  • Workflow Step (text field) – stores the number and label of the step being completed.
  • Workflow Action (text field) – stores the specific action step completed.
  • Event (multiple line text field) – stores details about the action completed.
  • AdminNotes (multiple line text field) – allows me to store specific notes for troubleshooting.

I configure my workflows to write an entry to the WorkflowLog everytime an important step is completed. If the workflow creates a new item and sets the status to ‘Created’, the next action is to create a new item in the workflow log and log that creation. Here is an example of the line item created by my Auto-increment ClientID workflow:

WorkflowName

AutoAssignClientID 

EventOccurred

5/15/2008 2:03 PM 

WorkflowStep

1 - Update ClientID then Increment ClientID 

WorkflowAction

Updated the ClientID on the new client 

Event

The workflow has taken the latest ClientID from the SystemCounters database and updated the Customer. Then it has incremented the SystemCounters by one.

AdminNotes

You can see, from the example, that I know that the workflow ran step 1 at 2:03pm on 5/15/2008. I know the step completed, and what it did. The link in the Admin Notes opens the original item so that I can check it. The workflow log allows you to easily troubleshoot a failed workflow – and it has the advantage that it works for Custom Form Actions (which have no history at all?).

Organising the Log

The log continues to compile workflow entries in the background as my users continue to work in the application. I can sort the log by the date the event occurred or by the workflow name, etc. I also have another field, specific to my company, which contains the “ticket number”. I can sort the workflow log by the specific ticket number, then the workflow name, and then the date and time. I have an admin page that contains a multiple item dataview of the log and allows me to select the ticket number from a drop-down list to filter the available entries. 

Future efforts

I am going to add a new column and link to the workflow. I want a column that stores a link to the actual SharePoint workflow history. If you open the workflow history on an existing item, the URL in the address bar looks like this:

http://mysharepointsite/sites/main/_layouts/Workflow.aspx?ID=72&List=B65934BA-EBF4-4CB8-956D-B0Ce4236B657 

The ID number identifies which specific entry the workflow was run on and the List number identifies which list the entry resides in. I will create a hyperlink that takes the ID from the current item (Dataview) and substitutes the List number as a variable as well.

I think that this log process contains a lot of untapped potential and I will be updating this post as I add to the log.

UPDATE

Paul Galvin pointed out that I forgot to mention some  of the possible downfalls to this logging method. You can see his blog here

Thanks for Reading

7 comments May 16, 2008

Create a Virtual Time Card System

Disclaimer: I found this tip on the web in a forum or site – but I can’t remember/locate the original source. If anyone knows the original source, please let me know.

I haven’t attempted this yet, and I would probably add some more detail to the instructions – but I want to get the basic idea up on the blog so I don’t lose the piece of paper I scribbled it on.

The Basic Scenario

The user clicks a button to “punch in” when the start work. The button creates a new item in a list and the system records the UserName, Time, Date, Department and TimeIn.

At the end of the workday, the user clicks the “punch out” button. The button creates a new item in a different list and that launches a workflow that edits the original item and recrds the UserName, Time, Date, Department and TimeOut. The workflow then populates a rich text field with the contents of both items.

At the end of the week, compile the contents of all of the records for all of the days of the week into one rich text field for the manager.

My Updates

Can the punch in process not be automated? When the user opens the Intranet Home page – you can grab the user logon credentials from server variables and then create the item automatically?

Instead of a rich text field with all of the records dumped into it, a multiple item dataview which is filtered by a drop-down (select username) would be much more organised.

Add an approval process and allow the manager to email the approved timesheets to the HR department – or send unapproved timesheets back to the original users to correct any mistakes. 

 

Add comment May 14, 2008

Design Tip 4: Turn Any Field in a Dataview into a Hyperlink

Any field in a Dataview (single or multiple item view) can be converted into a hyperlink to allow users to jump to the item in detail.

In one of the web applications I have created, the main page shows a customised multiple item Dataview that allows the user to see all of the currently open tickets and the status they are in. There are columns for Ticket Number, Edit Ticket, Comment, etc.

The Ticket Number is a hyperlink field that takes the user to a customised Dispform.aspx page where they can see a read only version of the ticket details. The Edit Ticket column contains hyperlinks to a customised Editform.aspx. The Comment column has hyperlinks which take the user to a customised Newform.aspx page to enter comments (in a different list).

The one thing that all of the lists in the application have in common is the Ticket number field. The hyperlink for the Comment column looks like this:

<a href=”http..sharepointsite/lists/newform.aspx&Ticket={@Title}” OnClick=”GoToLink(this);return false;”  target=”_self”>Comment</a>

Because the hyperlink is contained within a Dataview, you can access the variables from the dataview. The system will place the “Title” field value into the URL for the ticket I am clicking on. If I click the Comment hyperlink on ticket 12, it will place a 12 in the URL. The target form uses a Query String to access the Ticket variable and the new Comment is created for that ticket.

Click here to learn about defaulting values on a new item form:

http://splittingshares.wordpress.com/2008/04/22/defaulting-a-hidden-field-on-a-form/

Add comment May 14, 2008

Previous Posts


Recent Posts

Top Posts

Archives