|
|
-
Hi, Andy Lewis here again. I'm writing to share some tips on how to use SharePoint Designer to create workflows that leverage compound conditions and regular expressions. If you know your way around a SharePoint workflow, you know that you can use a workflow to examine the value of one or more fields in a list item, and then take actions based on a condition set by you. For example, you can have a workflow follow different paths depending on whether a text field contains a certain word.
One challenge you may face in building your application is being able to build (and maintain) a workflow that tests a field against a large number of valid values. If you have a really large number of values to match against, creating and managing the workflow can be a chore.
Or perhaps your needs are even more complex and you need to leverage the power of a regular expression. For example, you want to moderate message board content on your site to comply with various business rules or guidelines. One rule you have is that you want to exclude messages that contain links to sites other than your company's site. You want to allow links to http://www.contoso.com/products, but not http://www.wingtiptoys.com/catalog.
In this article I will demonstrate how to use a workflow to match list data against a compound condition and against a regular expression. I presume that you have designed a workflow before. If you are new to workflows, I recommend that you first consult Introduction to workflows before reading this article.
Match list data against a single compound condition
Suppose you want to check the Title of a list item to see if it contains one of several string values. For example, you want to see if one value from a long list of vehicle types appears in the Title field of a list item. In the Workflow Designer, you could express the condition this way:
But there is an easier way to express this kind of logic. You can load all the possible field values into the condition by using either || (for an "or" condition) or && (for an "and" condition). Here is how we can express the above conditions as a single condition:
Be careful when negating
One pitfall to avoid is using a negative condition in combination with an or condition. For example, suppose you wanted to negate the condition in the above example. You might try to express the condition this way:
This is probably not going to give you the result you want. The condition will always be true unless the title contains every one of these values! The kind of result you probably want is for the workflow to take an action if the Title does not contain at least one of the values in your list. You can express that intent by adding a new branch (an "else" condition):
Match list data against a regular expression
Suppose you work at Contoso and you want to make sure that no messages in your Announcement list contain links to sites other than your company's. If you (or a good savvy friend who owes you a favor) know how to write a regular expression, then creating a workflow to watch and alert you to messages that break this rule is easy.
By the way, regular expressions are also known as regex to those cool people who know how to write them, so henceforth I will use this very hip lingo. Not to say that I'm a regex expert or anything, but I am starting to learn some pretty nifty tricks you can do with them. Best of all, I can now impress my friends. Instead of saying "Is that string a valid email address?", I can now say, "Does that string match ("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$?" (Special thanks to whoever wrote MSDN Example: Confirming Valid E-Mail Format.)
Important: In a SharePoint workflow, the evaluation of whether a value matches your regex is done by the regex engine in the .NET system. So a good reference to use when coding a regex for a SharePoint workflow is this one: .NET Framework General Reference: Regular Expression Language Elements.
Design the regex
So here is the regex I came up with that is designed to find a hyperlink to a site other than those with the contoso.com host name:
https?://\S*(?<!\.contoso)\.com
Did you notice the slick negative look-behind in there ( (?<!\.contoso) )? That part says to look before the .com part of the URL and if it finds anything other than .contoso , then the link must be to a site other than contoso.com. Well maybe it is slick to some people, but not to those people who are not regex-gurus, such as whoever came up with that email example above. Anyway, the point is that coming up with the regex itself is in most cases the hard part. The next part is very simple, when you use SharePoint Designer to build the workflow that matches your regex against a value in a list item.
Create the workflow and set triggers
In SharePoint Designer, use the Workflow Designer to create a new workflow to watch the Announcements list for new or changed items:
Initialize the regex variable
We need to use the same regex more than once so that we can compare it against a few different Text fields. To reduce the potential for a bug in our workflow when changing the regex, we will put it in a workflow variable.
Of course instead of encoding the regex in the workflow itself, you could also initialize the variable using a workflow lookup from a SharePoint list. This alternative would give you the flexibility of being able to modify the logic of this workflow without having to actually use SharePoint Designer to open and modify the workflow itself.
Evaluate the message
The next and last step is simply to test whether any of the Text fields match the regex.
Now you have a workflow that screens any messages created in the Announcements list to make sure there are no links to sites not hosted on contoso.com. You could also instead use the Set Content Approval Status action to make the workflow either reject or approve the item. But keep in mind that the workflow runs at the permission level of the user who creates or changes the item, so this approval action will only work if the user who triggers the workflow has permission to approve items in that list.
Closing
Here are some next steps you might want to take:
- If you are inspired and want to know more about how you can use SharePoint Designer to create workflows, see the workflow topics on Office Online.
- If you find that none of the SharePoint Designer conditions meet a particular business need, one recourse is to create a custom condition. To get started, see the workflow topics on MSDN; in particular, Condition Element (WorkflowActions) describes the construct you will need to create. From there you can use the table of contents to find other helpful information. Note that to go this route, you will need the ability and permissions to create and deploy code on your SharePoint server.
- If you are an IT Pro and need to plan for using workflows in your organization, see Workflows roadmap.
That's all for now. Thanks for the time you spent reading this article; I hope you found it helpful. Please feel free to share the gnarliest regex you can think of that would be useful in a SharePoint application. See you next time!
|
-
Hello again. It's Jon again, with another tip to make your SharePoint Designer experience better when using external data. When using external data or large data sets in SPD, you can end up with slow performance while your data is retrieved and rendered. In SPD there is a built in way to make your life a little easier by using sample data instead of the real data. In doing so, you can save time by not using the network connection to request the data, but also time not having to render what can be a very large data set. Office Online has an article describing the basic steps to using sample data, but the downside of that method is that you end up with extremely generic data. (Note - this setting only applies to design time, it has no affect at runtime.) Let’s say you had an XML file with the following format: <?xml version="1.0" encoding="utf-8" ?> <trainingTimes> <trainingTime> <day>Tuesday</day> <StartTime>6:30pm</StartTime> <EndTime>8:30pm</EndTime> </trainingTime> <trainingTime> <day>Thursday</day> <StartTime>6:30pm</StartTime> <EndTime>8:30pm</EndTime> </trainingTime> <trainingTime> <day>Saturday</day> <StartTime>9:00am</StartTime> <EndTime>11:00am</EndTime> </trainingTime> </trainingTimes> If you were to drag the XML file onto the page, the default DataFormWebPart would look something like this:
Select the data view, then click the ">" icon in the upper right corner. In the "Common Data View Tasks" menu that is displayed, select "Show with sample data". The result will be as follows:
The sample data you see is fairly generic. However, you can do better. On the DataFormWebPart, there is a property called "Sample Data". You can set it by right clicking on your Data View, then selecting Web Part Properties.... Next, expand the Miscellaneous section. If you click the "..." next to the text box for sample data, you will be presented with an "Web Part Property Value" dialog where you can type or paste some XML. The idea is to input some representative XML data that will allow you to better visualize and style your data without the overhead of going to the real data source. In our case, we had a list of many training times, but for the sample data we only want a single training time (or perhaps a few). Paste the following into the box: <trainingTimes> <trainingTime> <day>Tuesday</day> <StartTime>6:30pm</StartTime> <EndTime>8:30pm</EndTime> </trainingTime> </trainingTimes> Then hit OK to both the "Web Part Property Value" dialog and the "Data View Properties" dialog.
Now your data exactly matches what your data source outputs. This technique can also be very useful for times when you want to do special formatting for a specific value, but your data source isn't providing such a value at a given time. Enjoy! -Jon
|
-
Hello all,
Stephen here again with a simple but useful workflow tip.
If you have used the out-of-box workflows included with MOSS, you have probably noticed that you can select which task list a workflow uses.
Unfortunately, the Workflow Designer in SPD does not provide this option this release. However, there is a relatively easy way to associate a specific task list with a specific SPD workflow.
The first time that you compile an SPD workflow, it is associated with a task list in the current site. This configuration information is stored in the wfconfig.xml file.
Changing this configuration information is not recommended or supported. However, you can determine which task list SPD will pick when you compile your workflow for the first time.
How does SPD pick a task list?
If there is more than one task list in a site, SPD picks the first task list that is returned in the list of lists from the server — and this list of lists is sorted alphabetically by list name.
View your site in the browser, and then click View All Site Content. On the All Site Content page, you can see that any SPD workflows created in this site will be associated with the AAA Tasks list, instead of the default Tasks list. Why? Because it is the first task list to appear alphabetically in the list of lists.
So to associate an SPD workflow with a specific task list, simply do the following:
-
In the browser, create a new task list and name it so that it appears first alphabetically in the list of lists on the All Site Content page.
- In SPD, create a new workflow and compile it (click Finish in the Workflow Designer).
-
In the browser, rename the new task list so that at least one other task list appears above it alphabetically on the All Site Content page – for example, name it "Workflow Tasks," as shown here.
As long as at least one other task list appears alphabetically above your new task list, subsequent workflows created in SPD will not be associated with the new task list. In effect, you have associated a specific SPD workflow with a specific task list, and then reserved that task list so that other SPD workflows will not use it.
Why is this useful? Here are a couple of scenarios:
- Your workflow uses the Assign a Form to a Group action. The information that workflow participants submit in the form is stored in items in a task list. To make this information easier to view and report, you want this workflow to have its own dedicated task list.
- Your workflow uses the Collect Data from a User action. You want the task notifications for this workflow to have more specific instructions than those provided by the default automatic task notifications. So you want a secondary workflow running on a task list to send custom task notifications. To do this, you need to turn off the automatic task notifications on the task list — but you don't want to turn off these notifications for other workflows running in the site, just this workflow. So this workflow (and its secondary workflow) requires a separate task list.
There are many more reasons why you might want to associate a workflow with its own task list. So enjoy.
Cheers, Stephen
|
-
Hi folks. This is Greg Chan, Program Manager in the SharePoint Designer team. For those of you who attended the SharePoint Conference last month in Seattle, you may remember me as the speaker for the session - "Building a SharePoint Designer 2007 Mashup". I promised you guys that I would post a blog about the demos I gave during the presentation. So here it goes! For those of you who missed out on that session, you should definitely check this out as well! Everyone loves mashups. Why? They're fun, they're useful and they're slick, and being able to build one gives you instant street cred! :) So, how do we build one in SharePoint? Let me show you. Below are the 2 demos I gave on mashups: - Building an advanced form with a related-item view and the Windows Live Map control
- Building an advanced view with ASP.NET calendar control, data view and the MSN Weather RSS Feed. (Covered in Part 2)
(I also gave a quick demo around workflow, but that won't be covered in this post.) Background info on the demos Some of the content in this demo will be similar to things covered in previous blogs. For those of you who have been keeping up with all the SharePoint Designer blogs, you may already be an expert at this. For both demos, I used this scenario - you run a golf course and a golf shop and you want to use SharePoint to help manage this business. You start out with just a basic team site with some data filled in. There's the "Golf Equipments" list that tracks all the Golf Equipment you sell at the store. There's a "Suppliers" list that shows the suppliers for each of the golf equipment. And, there's a standard "Calendar" list, that shows the scheduled tee times for the golf course. Demo #1 - Building an advanced form with a related-item view and the Windows Live Map control In the first demo, I customized the display form of the "Suppliers" list to show more helpful information. 1) Created a related-item view that shows all the golf equipment supplied by the current supplier 2) Created a map view that shows the location of the current supplier. For the related-item view of golf equipments Here are the steps: 1) Open the DispForm.aspx page for Suppliers in SharePoint Designer. 2) In main menu go to Task Panes->Data Source Library. 3) In the Data Source Library, drag and drop the "Golf Equipments" list into the page, below the list form web part. 4) Click the OOUI button in the data view to bring up the Common Data View Tasks menu. 5) (optional) You can pick "Edit Columns" to modify the columns to display. *Note - We have now inserted a data view showing us all the golf equipments in the list. But that's actually not what we want. We want to filter this view to show only golf equipments supplied by the current supplier. To do this, we need to filter the view. 6) Click "Filter" option. 7) Set Field Name=Supplier, Comparison=Equals 8) For Value, select "Create a new parameter" option. 9) Create a new parameter - Parameter Name = "SupplierID" - Parameter Source = Query String - Query String Variable = ID - Default Value = 1 (or whatever default value you like) - Hit OK until you get back to design view * Note - This is the ID parameter that is always in the query string section of the URL of any standard SharePoint form (New/Edit/Display forms). Each ID maps to a unique item in the list and that is what we'll use to filter our view. *Note - Now you'll notice that the data view actually doesn't show anything. The reason is, the "Supplier" field in the Golf Equipments list is a lookup field. By default, the value of the lookup field is returned as a text string. But in our scenario, we actually want to use the ID value of the lookup to drive our filtering, and not the text string. In order to have the lookup field return the ID value, there's a great advance step you can do. 10) Switch over to Code View 11) Go to the top of the document and do a find for "SupplierID" 12) You will be taken to the <SharePoint:SPDataSource...> tag, which is the markup that defines the data source for the data view. In there is an attribute called "selectcommand" which basically tells the data source what fields to return. The markup inside looks a little messy, but that's only because all the <, > and quotes are escaped. So, don't be scared! In there you'll find the FieldRef for the Supplier field. All you need to do is add this extra attribute in there - LookupId='TRUE'. This will tell the data source to return the Supplier lookup value as an ID instead of text. For example: | <SharePoint:SPDataSource runat="server" DataSourceMode="List" UseInternalName="true" selectcommand="<View><Query><Where><Eq><FieldRef LookupId=’TRUE’ Name="Supplier"/><Value Type="Text">{SupplierID}</Value></Eq></Where></Query></View>" id="Golf_x0020_Equipments1"> | Ok, now you're done. If you switch back to design view, you'll see the data view displaying all the golf equipments supplied by the current supplier. Don't forget to save the page and check it out on the browser :) For the map view displaying the location of the current supplier I actually already covered this topic in a previous blog post on this a few months ago. Check out - http://blogs.msdn.com/sharepointdesigner/archive/2007/06/15/how-to-integrate-virtual-earth-maps-with-a-sharepoint-list.aspx. The scenario and steps are almost identical. To be continued: Alright, you should now have a pretty nifty mashup as your display form that shows you both the golf equipment supplied by the current supplier and an interactive Windows Live Map view that displays the location of the supplier. See how easy that was to turn a standard (and dare I say boring...) form into an advanced mashup?! Within the next couple of weeks, I will post a blog on the 2nd demo - Building an advanced view with ASP.NET calendar control, data view and the MSN Weather RSS Feed. Stay tuned! Greg
|
-
Hi, I'm Andy Lewis, and I'm delighted to be joining the fine company of the various folks who have already posted to the SharePoint Designer blog. My current role is to write user assistance content for SharePoint Designer. In past jobs, I've designed and coded web applications, including both server and client code. I tend to get most interested in the user experience part of a software application, but of course the nuts and bolts of creating that experience are what make working in software challenging (and thus fun!). I'm here today to share ideas and some code that can help you work with dates in a Microsoft Office SharePoint Designer application.
Whatever data source you use in your application (SharePoint list, SharePoint library, database connection, etc.), you almost certainly will need to work with date values. For example, a SharePoint library has built-in fields to track when an item was created and when it was modified. And you might create your own date field in a list or table to designate when an item is due to a stakeholder, or when you estimate it will be done, or when it was completed.
Displaying a date value in a Data View is a fairly simple matter; you add it as you would any other column. If SharePoint Designer detects that the column holds date values, it automatically adds extra formatting (which you can customize) to properly display the date, and optionally the time. But filtering or conditionally formatting based on date values is a more complex capability to build.
In this article I'll show you how to build rich date-value capabilities with minimal effort. This article will:
- Walk you through some of the most common date-value scenarios and show you how to use SharePoint Designer to make them work. Specifically, we will:
- Show you how to Create a blank Data View
- Provide you with a library of date-oriented XSL templates that you can copy and paste directly into your SharePoint solution. This information includes:
Here are some code format conventions you will see in this article: <p>This is code you need to add within this code block.</p>
<p>This is code you need to delete within this code block.</p>
<p>The ellipses that follow indicate code that continues after this point
but is truncated ...
Note: Some of the material that explains how to perform the more basic tasks is hidden from view by default if you have JavaScript turned on. If you want to print this article with all the material included, click here: Show All.
Conditionally format items between today's date and a calculated date field value
Suppose you have a large document library and want emphasize those items that have been recently modified (within the past 15 days) so that it is easier for your customers to notice and then optionally look at whatever changes were made to those documents. You decide to use conditional formatting rather than a filter because you want to show the documents in the way your customers typically want to see them, with all the documents shown grouped by project.
The final result could look something the following image, in which documents modified in the past 15 days show the Modified date highlighted in green:
A calculated field is one mechanism you can use to determine a date range that is defined on one end by a today's date and on the other end by a date that is n days before or after today's date.
Format of calculated date field is different than standard date field
There is one wrinkle to using a calculated field for this purpose. The actual format of the data returned by a calculated date field is MM/DD/YYYY. The conditional formatting feature of SharePoint Designer expects to get the data in ISO format (YYYY-MM-DDTHH:MM:SSZ). For, example if the date value is 11/30/2007, then the format of the data returned from a SharePoint list would be:
- From a Date and Time field (Date Only) in the Pacific time zone: 2007-11-30T08:00:00Z
- From a Calculated date field (Date Only): 11/30/2007.
To deal with this inconsistency, we will tweak the XSL code generated by the SharePoint Designer conditional formatting feature, and leverage one of the XSL templates in the date template library shown below.
Steps
-
Create the Modified_Recently calculated field with a formula of [Modified] + 15. How?
- From your document library, click Settings and then choose Document Library Settings.
- Under Columns, click Create column.
- In the Column name field, type Modified_Recently.
- Choose Calculated (calculation based on other columns).
- In the Formula field, type [Modified] + 15.
- Choose Date and Time under The data type returned from this formula is. Also, make sure Date Only is selected under Date and Time Format.
- Click OK.
-
Create a list view. For example:
-
Convert the list view to a Data View. How?
- Open the ASPX page that contains the list view in SharePoint Designer.
- In Design view, right-click the ListViewWebPart object and choose Convert to XSLT Data View.
- Click File and choose Save. When the Site Definition Page Warning is displayed, click Yes.
-
Apply conditional formatting that displays the value in the Modified column with a background color of green (#00FF00) when Modified_Recently Greater Than Or Equal [Current Date]. How?
- In Design view, in the Data View, select one of the values in the Modified column.
- Click Data View and then choose Conditional Formatting.
- In the Conditional Formatting task pane, click Create, and then click Apply Formatting.
-
In the Condition Criteria dialog box, specify this criterion:
and then click OK.
-
Make the background green (or whatever formatting you want to use) when a document has been recently modified:
and then click OK.
- You observe that the conditional formatting you applied had no effect. This is because of the date format issue discussed earlier. In the next steps we will fix this problem.
-
Make the convertCalcDateValue template available to the XSL stylesheet in your Data View. See Make the date templates available to your Data View for information on how to do this.
- Find the XSL code that displays the Modified field. One way to do this is to switch to Split view and select one of the values in the Modified column.
- Create a variable that reformats the Modified Recently value from MM/DD/YYYY format to ISO format (YYYY-MM-DDTHH:MM:SSZ).
<TD Class="{$IDAAOPHB}">
<xsl:variable name="Modified_Recently_ISO">
<xsl:call-template name="convertCalcDateValue">
<xsl:with-param name="paramDate" select="@Modified_Recently"/>
</xsl:call-template>
</xsl:variable>
<NOBR><span>
<xsl:attribute name="style">
<xsl:if test=" number(translate(substring-before(@Modified_Recently$Modified_Recently_ISO,'T'), '-',''))
>= number(translate(substring-before($Today,'T'),'-',''))">
background-color: #00FF00;
</xsl:if>
</xsl:attribute>
<xsl:value-of select="ddwrt:FormatDate(string(@Modified) ,1033 ,1)" />
</span></NOBR>
</TD>
The calculated field method has several limitations:
- This approach works only if your data source is a SharePoint list or library. If your data source is database connection or the Business Data Catalog, then you need another solution (see the following sections).
- You need a field for each date value that needs to be part of a date range. So for example, if you wanted to show different colors depending on how recently a document was modified, you would need a different calculated field for each date range.
- You cannot specify date ranges such as "last quarter" or "next month".
Despite these limitations, the example above illustrates how the convertCalcDateValue template gives you a way to take the value from a calculated date field and work with it in a Data View to do conditional formatting. You can also use this template to do filtering or whatever else you need to do with value from a calculated date field.
Next, I'll describe how to do conditional formatting using a pure XSL solution with no calculated field needed.
Conditionally format items based on date range
Suppose you want to give your customers better visibility of documents that require attention because they are not yet complete and they are either due soon (for example, within 15 days) or overdue. You want to offer a Data View that looks something like this:
Note: In the above example, assume that today's date is 1/3/2008.
Although our example for this section is a SharePoint document library, the techniques in this section will work for any kind of data source (database connection, Business Data Catalog, and so on). Here is how you build this kind of view:
-
Create a list view with the fields and grouping as shown in the above screenshot.
-
Convert the list view to a Data View. How?
- Open the ASPX page that contains the list view in SharePoint Designer.
- In Design view, right-click the ListViewWebPart object and choose Convert to XSLT Data View.
- Click File and choose Save. When the Site Definition Page Warning is displayed, click Yes.
-
Make the date templates available to your Data View. For information on how to do this, see Make the date templates available to your Data View.
-
Make sure the ParameterBinding named Today is included in the ParameterBindings tag of the Data View. How?
- In Code view, find the ParameterBindings start-tag.
- Make sure <ParameterBinding Name="Today" Location="CAMLVariable" DefaultValue="CurrentDate"/> is in the contents of the <ParameterBindings> element.
-
Make sure the Parameter named Today is included in the XSL style sheet of the Data View. How?
- In Code view, find the xsl:stylesheet start-tag.
- Make sure <xsl:param name="Today"/> comes somewhere after the xsl:stylesheet start-tag and before the first xsl:template element within the stylsheet.
- Find the XSL code that displays the Date_Due field. One way to do this is to switch to Split view and select one of the values in the Date_Due column.
-
Use the dueDateDelta template to add conditional formatting to the the Date_Due field by adding the highlighted code: <!--Date_Due-->
<TD Class="{$IDABW30D}">
<!-- if this document is not complete -->
<xsl:if test="@Status != 'Complete'">
<!-- get the delta in days between the due date and today -->
<xsl:variable name="dueDateDelta">
<xsl:call-template name="getDayDelta">
<xsl:with-param name="paramDateA" select="@Date_Due"/>
<xsl:with-param name="paramDateB" select="$Today"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<!-- if due date is before today, then document is
overdue, so highlight in red -->
<xsl:when test="$dueDateDelta < 0">
<xsl:attribute name="style">background-color:#FF0000;</xsl:attribute>
</xsl:when>
<!-- if due date within 15 days after today, then document is
due soon, so highlight in yellow-->
<xsl:when test="$dueDateDelta < 15">
<xsl:attribute name="style">background-color:#FFFF00;</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:if>
<NOBR>
<xsl:value-of disable-output-escaping="no" select="ddwrt:FormatDate(string(@Date_Due),number($Language),1)" />
</NOBR>
</TD>
Notice that we used a slightly different visual effect in this example than in the prior example. We light up the entire table cell, which may be more noticeable than in the previous example, where we used a span to restrict the conditional formatting to highlight just the text inside the table cell. Suppose you wanted to make the effect even more noticeable by highlighting the entire row:
To do this, you simply need to move the xsl:if block just below the tr tag (How?):
The code would look something like this (new code is highlighted): <TR style="display:{$dvt_GroupStyle}">
<xsl:if test="position() mod 2 = 0" ddwrt:cf_ignore="1">
<xsl:attribute name="class">ms-alternating</xsl:attribute>
</xsl:if>
<!-- if this document is not complete -->
<xsl:if test="@Status != 'Complete'">
<!-- get the delta in days between the due date and today -->
<xsl:variable name="dueDateDelta">
<xsl:call-template name="getDayDelta">
<xsl:with-param name="paramDateA" select="@Date_Due"/>
<xsl:with-param name="paramDateB" select="$Today"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<!-- if due date is before today, then document is overdue, so highlight in red -->
<xsl:when test="$dueDateDelta < 0">
<xsl:attribute name="style">background-color:#FF0000;</xsl:attribute>
</xsl:when>
<!-- if due date within 15 days after today, then document is
due soon, so highlight in yellow-->
<xsl:when test="$dueDateDelta < 15">
<xsl:attribute name="style">background-color:#FFFF00;</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:if>
After you create this Data View, there are a lot of ways you could further enhance it. For example, for overdue items you could offer a link that sends mail to the owner of the document requesting more information.
Filter to show items within a date range
Now for our trickiest and most interesting scenario: filtering a Data View based on a date range. Although you can directly filter a Data View in a number of ways, when it comes to filtering a Data View based on a date, the only option available out of the box is to filter items based on a date value relative to today. So you can quickly create a Data View that answers questions like these:
- Is date_due before today?
- Is date_due equal to or after today?
But typically web applications need to answer date-oriented questions such as these:
- What work is due in the next 60 days?
- What work is due between date A and date B?
- What work did we complete last month?
- What work did we complete last quarter?
In order to answer these kinds of business questions, you need to do some extra work to filter your Data View.
Create a Data View that shows documents due in various date ranges
For this example, we will create a Data View that can show items that are due within a few different ranges:
The following steps describe how to create this kind of Data View.
-
Create a list view with the fields and grouping as shown in the above screenshot.
-
Convert the list view to a Data View. How?
- Open the ASPX page that contains the list view in SharePoint Designer.
- In Design view, right-click the ListViewWebPart object and choose Convert to XSLT Data View.
- Click File and choose Save. When the Site Definition Page Warning is displayed, click Yes.
-
Apply a filter to the Data View so that it shows only items in which Date_Due is greater than or equal to [start] and less than or equal to [end], where [start] and [end] are Query String parameters. How?
- Click the Data View, and then click the arrow
in the upper-right corner.
- In the Common Data View Tasks list, click Filter.
- In the Filter Criteria dialog box, create the first condition of the filter criteria:
- Click Click here to add a new clause....
- In the Field Name column, select Date_Due.
- In the Comparison column, select Greater Than Or Equal.
- In the Value column, select Select Create a new paramter.
- In the Data View Parameters dialog box, type start.
- From the Parameter Source field, select Query String.
- In the Query String Variable field, type start.
- In the Data View Parameters dialog box, click OK.
- In the Filter Criteria dialog box, create the second condition of the filter criteria:
- Click Click here to add a new clause....
- In the Field Name column, select Date_Due.
- In the Comparison column, select Less Than Or Equal.
- In the Value column, select Select Create a new paramter.
- In the Data View Parameters dialog box, type end.
- From the Parameter Source field, select Query String.
- In the Query String Variable field, type end.
- In the Data View Parameters dialog box, click OK.
-
The final result looks like this:
- Add some room above the Projects Data View by inserting a few paragraphs above it.
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<p></p>
<p></p>
<p></p>
<WebPartPages:DataFormWebPart ...
- Create a blank Data View by dragging it above the Projects Data View. For detailed steps, see Create a blank Data View.
- Make the supplemental date templates available to your blank Data View. For detailed steps, see Make the supplemental date templates available to your Data View.
- Replace the contents of the <xsl:template> tag inside the blank Data View with the following code.
<xsl:template match="/">
<p style="margin:.5em 0 .5em .5em">Choose a date range:</p>
<ul style="margin:0 0 1em 3em">
<li>
<a>
<xsl:attribute name="href">
<xsl:text>Due_Dates.aspx?</xsl:text>
<xsl:text>start=</xsl:text>
<xsl:call-template name="getDateRange">
<xsl:with-param name="paramBaseDate" select="$Today"/>
<xsl:with-param name="paramRangePeriod">LAST</xsl:with-param>
<xsl:with-param name="paramRangeType">MONTH</xsl:with-param>
<xsl:with-param name="paramRangeBoundary">START</xsl:with-param>
</xsl:call-template>
<xsl:text>&</xsl:text>
<xsl:text>end=</xsl:text>
<xsl:call-template name="getDateRange">
<xsl:with-param name="paramBaseDate" select="$Today"/>
<xsl:with-param name="paramRangePeriod">LAST</xsl:with-param>
<xsl:with-param name="paramRangeType">MONTH</xsl:with-param>
<xsl:with-param name="paramRangeBoundary">END</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<xsl:text>Last month</xsl:text>
</a>
</li>
<li>
<a>
<xsl:attribute name="href">
<xsl:text>Due_Dates.aspx?</xsl:text>
<xsl:text>start=</xsl:text>
<xsl:value-of select="substring-before($Today,'T')"/>
<xsl:text>&</xsl:text>
<xsl:text>end=</xsl:text>
<xsl:call-template name="getDateFromDays">
<xsl:with-param name="paramBaseDate" select="$Today "></xsl:with-param>
<xsl:with-param name="paramDelta">30</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<xsl:text>Next 30 days</xsl:text>
</a>
</li>
<li>
<a>
<xsl:attribute name="href">
<xsl:text>Due_Dates.aspx?</xsl:text>
<xsl:text>start=</xsl:text>
<xsl:value-of select="substring-before($Today,'T')"/>
<xsl:text>&</xsl:text>
<xsl:text>end=</xsl:text>
<xsl:call-template name="getDateFromDays">
<xsl:with-param name="paramBaseDate" select="$Today "></xsl:with-param>
<xsl:with-param name="paramDelta">60</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<xsl:text>Next 60 days</xsl:text>
</a>
</li>
</ul>
</xsl:template>
Move filter links to left nav area
It is not a great use of page real estate to have the links appear over the Data View. A better UI design would be to have the links appear in the left navigation area, highlighted in red below:
The following steps describe how to put these links in the left navigation bar.
-
Create a new master page by copying and modifying default.master. Add a new content placeholder called PlaceHolderDataViewParameters. ...
<td valign="top" width="100%">
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBarDataSource" runat="server" />
<asp:ContentPlaceHolder id="PlaceHolderCalendarNavigator" runat="server" />
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBarTop" runat="server"/>
<asp:ContentPlaceHolder id="PlaceHolderDataViewParameters" runat="server" />
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBar" runat="server">
...
(For a detailed explanation of how to copy and modify the default master page, see Modify the default master page.)
-
Edit the content page you created in the previous section in Code view and add the PlaceHolderDataViewParameters content placeholder to the content page. <asp:Content ContentPlaceHolderId="PlaceHolderDataViewParameters" runat="server">
<div class="ms-quicklaunchouter">
<div class="ms-quickLaunch" style="width:100%;">
<WebPartPages:DataFormWebPart ... />
...
</WebPartPages:DataFormWebPart>
</div>
</div>
</asp:Content>
Note that to make the presentation nicer and consistent with the default SharePoint site look and feel, we use a few nested div tags.
- Move the Data View you created into the new content placeholder.
Final comments on date range filtering
One advantage of the approach described above is that it filters the data at the database layer of the application. You could use the Add XSLT Filtering checkbox in the Filter Criteria dialog box to accomplish a similar result, but you would have several potential issues if you use that model. For large sets of data, performance would suffer and the load on the database server would be higher. You would also need to create multiple pages, one for each filter you want to use, rather than being able to leverage a single page for all of the filters you need to offer your users.
Hack the CAML query to filter for items within a date range relative to today
I know this sounds violent, but I promise this procedure does not involve harming animals. As discussed above, you can use the Filter Criteria dialog box to restrict a Data View to showing only list items with date values before, on, or after today. But it does not let you filter to show list items with a due date that is either due soon (say within 15 days from today) or overdue (in the past). There is a fairly simple workaround for this limitation.
-
Create a Data View and apply the following filter in the Field Criteria dialog box: Date_Due Less Than Or Equal [Current Date].
-
In Code view, find the SharePoint:SPDataSource tag. Within that tag, find the selectcommand attribute. It should look something like this: <SharePoint:SPDataSource
...
selectcommand="<View><Query><OrderBy><FieldRef Name="Date_Due"
Ascending="TRUE"/></OrderBy><Where><Leq><FieldRef Name="
Date_Due"/><Value Type="
DateTime"><Today/></Value></Leq></Where></Query></View>"
...
>
- Let's make a few harmless text replacements to the selectcommand attribute to make it more readable:
<SharePoint:SPDataSource
...
selectcommand="<View><Query>
<OrderBy><FieldRef Name='Date_Due' Ascending='TRUE'/></OrderBy>
<Where><Leq><FieldRef Name='Date_Due'/><Value Type='DateTime'><Today/></Value>
</Leq></Where></Query></View>"
...
>
- Add the OffsetDays attribute to the Today element and set its value to a negative integer to yield a date n days before today or a positive integer to yield a value n days after today. For this example, we want to show items due before 15 days after today.
<SharePoint:SPDataSource
...
selectcommand="<View><Query>
<OrderBy><FieldRef Name='Date_Due' Ascending='TRUE'/></OrderBy>
<Where><Leq><FieldRef Name='Date_Due'/><Value Type='DateTime'><Today OffsetDays='15'/></Value>
</Leq></Where></Query></View>"
...
>
For more information on CAML syntax, see Collaborative Application Markup Language (CAML).
Filter a SQL Server Database Connection relative to today
I recently created a Data View of a SQL Server database connection and tried to filter the records relative to today's date. For example, to show all records where Date_Due is equal or greater than today's date. There is an issue with the Filter Criteria dialog box so that when you try to set this up, the Data View fails, showing this message in Design view: The server returned a non-specific error when trying to get data from the data source. Check the format and content of your query and try again. If the problem persists, contact the server administrator.
I found a workaround by looking up the literal that SQL Server uses to represent today's date. So after you create a Data View and apply the filter using the Filter Criteria dialog box, go into Code view and in the SelectCommand attribute, replace @Today with CURRENT_TIMESTAMP. For example: <asp:SqlDataSource
...
SelectCommand="SELECT * FROM [vw_ProjectDocs] WHERE [Date_Due] >= @Today CURRENT_TIMESTAMP"
>
Create a blank Data View
Sometimes it's handy to be able to dynamically render HTML at runtime. For example, you might need to create a hyperlink that includes today's date as a query string argument. You can use a Data View to obtain data such as today's date or arguments from the page's query string. You can use its XSL parser to then render HTML using XSL's various capabilities (string manipulation, math functions, conditional logic, etc.)
Following are the steps to create a blank Data View.
- Copy the the following text into a blank text file and save it as blankdv.xml.
<?xml version="1.0" encoding="utf-8" ?>
<item></item>
- Edit the .aspx page where you need the dynamic HTML generation and switch to Design view.
- From the Data Source Library task pane, drag blankdv.xml onto the place in the page where you need the dynamically-rendered HTML.
Because we don't plan to show any data, we want to make the code of the Data View as small and simple as possible to make adding our custom XSL as simple as possible. One way to do this follows.
- Click the Data View, and then click the arrow
in the upper-right corner to show the Common Data View Tasks list.
-
On the Common Data View Tasks list, choose Change Layout. Then, in the Data View Properties dialog box, choose the plain list layout.
- Click OK.
- In Code view, make the following modifications to the XSL block in the Data View.
<XSL>
<xsl:stylesheet version="1.0" exclude-result-prefixes="xsl msxsl ddwrt"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:SharePoint="Microsoft.SharePoint.WebControls"
xmlns:ddwrt2="urn:frontpage:internal">
<xsl:output method="html" indent="no"/>
<xsl:decimal-format NaN=""/>
<xsl:param name="FileName" />
<xsl:param name="dvt_apos">'</xsl:param>
<xsl:param name="Today"/>
<xsl:variable name="dvt_1_automode">0</xsl:variable>
<xsl:template match="/">
<xsl:call-template name="dvt_1"/>
Hello World!<br/>
Today is <xsl:value-of select="$Today"/>. <br/>
Put your content here.
</xsl:template>
<xsl:template name="dvt_1">
<xsl:variable name="dvt_StyleName">NumTitl</xsl:variable>
<xsl:variable name="Rows" select="/item" />
<ol>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows" />
</xsl:call-template>
</ol>
</xsl:template>
<xsl:template name="dvt_1.body">
<xsl:param name="Rows" />
<xsl:for-each select="$Rows">
<xsl:call-template name="dvt_1.rowview" />
</xsl:for-each>
</xsl:template>
<xsl:template name="dvt_1.rowview">
<li class="ms-vb">
<xsl:value-of select="text()" />
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<br /><span ddwrt:amkeyfield="" ddwrt:amkeyvalue="string($XPath)" ddwrt:ammode="view" />
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
</XSL>
</WebPartPages:DataFormWebPart>
- Replace the content of the <xsl:template> tag with your content.
SharePoint Designer Supplemental Date Templates
This section provides the date templates you need to build date filtering and date-driven conditional formatting features into your Data Views. You might reasonably ask whether it makes sense to use XSL this way; why not just use ASP.NET code, where a rich API provides a wealth of calendar-oriented functionality. And if you can put code on a server, then that option could make sense.
But for those of us who don't have our own server, or who don't have the permissions to put code on a server, then the date templates in this section provide a way for you to expand the kind of applications you can build with nothing more than the Full Control permission level in a SharePoint site plus SharePoint Designer. Furthermore, it is generally expensive to create and maintain custom ASP.NET code, and there is additional security risk as well. If you can stretch a Data View to do what you need, then you can save yourself a lot of trouble.
Capabilities provided by these templates
By copying these templates into your SharePoint site, you get the benefit of these capabilities:
-
Convert a calculated field value into ISO format (convertCalcDateValue)
-
Get number of days between two dates (getDayDelta)
-
Get start and end dates for various date ranges relative to today such as last month, next month (getDateRange)
-
Get date that is n days before or after a date (getDateFromDays)
-
Various utility templates
Note: getDateFromDays is not leap-year accurate. So while I have not yet solved this problem, if you can think of a good solution, I encourage you to post it as a comment to this article.
Make the date templates available to your Data View
There are two ways to make the date templates available to your Data View:
- Copy the templates into a separate .xsl template file and add an xsl:import tag to your Data View.
- Copy the individual templates you need into the XSL block of the Data View.
Copy the date templates into the Data View
If you want to quickly and simply pull the templates into a Data View, perhaps to try them out, you can simply copy them into your Data View directly.
- Select the templates you want to use (including any templates that they call) in the Template Code section of this article and copy them to the clipboard.
- In SharePoint Designer, edit the page that contains your Data View in Code view, put the cursor before the first xsl:template start-tag in the Data View, and then paste the templates into the Data View.
Create and use date templates by importing from a separate file
This method is efficient and has the advantage of letting you use the same set of templates from multiple Data Views in multiple pages in your site. If you need to enhance or add to the templates for your own needs, having them in a single file means you have to modify them in only one place.
Important: There seems to be a problem with using this method if you created your Data View by converting a list view to the Data View. The page renders OK in the web browser, but fails to render visually in Design or Split view in SharePoint Designer. So one way to work around this issue is to copy the templates into your Data View until you are done designing it, and then as a last step, switch to using the import method described below.
First create the file:
- In SharePoint Designer, click File, and then click New.
- Click General, and then click Text File.
- Switch to this browser window, select the templates in the Template Code section of this article and copy them to the clipboard.
- Switch to SharePoint Designer and paste the templates into the new text file.
- Click File, and then click Save.
- Save the file to the directory where you want it to be stored, with the name you want to give it (for example http://mysite/shared_templates/date_templates.xsl.
Next import the date templates into your Data View so that you can use them in your XSL code:
- Edit the page that contains your Data View in Code view and find the xsl:stylesheet start-tag.
- Insert a new xsl:import tag immediately after the xsl:stylesheet start-tag. For example, if the page that contains your Data View is http://mysite/reports/due_dates.aspx, and the date templates are stored in http://mysite/shared_templates/date_templates.xsl, then you would modify your Data View as follows:
<xsl:stylesheet ...
<xsl:import href="../shared_templates/date_templates.xsl"/>
<xsl:output method="html" indent="no"/>
...
Template Code
Attached to the bottom of this article is the XSL code for the date templates. I recommend you download it rather than view it in your web browser. In Internet Explorer, you can download it by right-clicking the date_templates.xsl link and choosing Save Target As.
Conclusion
I hope you find the material in this article useful. I want to give special thanks to John Jansen, Rob Howard, Eray Chou, and Les Smith for their contributions, suggestions, and tips for this article. I look forward to hearing your feedback and questions, and especially to seeing your solution to make the getDateFromDays template leap-year accurate!
|
-
Hi again, John here with a post that I hope will help out a lot of people. The scenario is simple: You have just used SharePoint Designer to insert a Data View of some list. You have formatted the fields to be SharePoint:FormField controls, and now you want to change the size of those controls. Why is this so hard? Well, the controls are rendered from the server (as are all asp.net controls) and so the markup (or HTML) used to make them display in the browser cannot be directly manipulated on the SPD design surface. What we need to do is determine the class SharePoint uses to render the size of the controls, and then override it via CSS. For this demo, we'll use the default Title field from the default Announcements list. These steps also assume that you know how to create new pages and insert views on them. - Make sure you have at least one announcement in your Announcements list
- Open your site in SharePoint Designer
- Create a new page based on the Master page
- Click on Task Panes > Data Source Library
- Click on the Announcements list and click Show Data
- Select the Title data value
- Click Insert Selected Fields as > Single Item Form
- Save the page and press F12 to Preview in Browser
- Right click the page in the browser and click View Source
- Select All > Copy
- Create another new page in SPD and Paste all of the content into this new page's Code View
- Click back into Design View
- Select the Textbox control for the Title field
At this point you can see that the class on this field is called ms-long. This is the class we need to override. So for other controls, we just want to follow the same steps above. By getting the server generated HTML from the browser in step 10, we are able to use all of SPD's tools to understand the HTML. I do this a lot when dealing with the customization of server controls. Now we just need to add a <style> block inside our first page that says something like below, then save the page.: <style> .ms-long{width:100px;} </style> This will make the textboxes on this page 100 pixels wide. If you want to know more about CSS in general, check out the information on the Microsoft SPD Site. If you want to know more about Core.CSS in SharePoint, check out this Style Guide. Good luck! -John Jansen Test Lead, SharePoint Designer
|
-
Hi everyone,
If you're having trouble with Delay activities not returning in SharePoint workflows, head over to this entry from the SharePoint team blog for status and information on how to help us identify the issue:) Thanks much!
-Eilene
|
-
Hi everyone, Jon here again. Today I wanted to show you how to use Conditional Formatting to really spice up your data views. Preparation The customizations that I am going to demonstrate revolve around the creation of a product ordering page. To start, I created a SharePoint list called Products to store my data, though you could just as easily hook up into a database or other data source. I created the following fields: I then filled in the table to have some sample values. If you are using your own datasource, be aware that the field names will be different, but the concepts will remain true. When doing conditional formatting, the biggest pre-requisite is that you need to be using a data view to display your data. There are a couple ways to create a data view, so if you haven’t done it before I suggest checking out the documentation on Microsoft Office Online. Show/Hide One of the easiest ways you can use conditional formatting is to show or hide something in your data view based on some condition. In the case of the above table, we might want to show *SALE* next to any item that has a discount associated with it. The first thing you will want to do is insert whatever it is you want to show or hide. Next, right click in your data view and select Conditional Formatting… to bring up the Conditional Formatting task pane. Highlight the text you want to hide (*SALE* in our case), then click the Create button in the conditional formatting task pane. Select the Hide Content… option, which will bring up a dialog for setting your criteria. Since the Discount field can be zero or empty, make the condition be “Discount Is Null OR Discount Equals ‘0’”. You can now save the page and view the results in your browser. Advanced Show/Hide Now that we have the basics of creating a condition down, we can add something a little more interesting. On many ecommerce sites you will see text on certain items indicating “Only 5 Left!” or “Last One!” in the listing. Creating the text for “Last One!” is the same as what we did for sale – insert your text, highlight it, then click the Create button. Instead of selecting Hide, select Show since most of the time there will be more than one item. For the condition choose “Stock Equals 1”. To create the “Only 5 Left!” insert the text, then drag the Stock field from the Data Source Details task pane and drop it next to the number 5. Once you delete the 5, you now can select the text and repeat the same steps for the Show option, but choose “Stock Less Than 10 AND Stock Greater Than 1”. The reason we have the second clause is that we don’t want to show the text when we are already showing the “Last One!” text, nor do we want to show it for items that are out of stock. KPIs and Icon Sets using "Apply Formatting" SharePoint Designer 2007 doesn’t have the same icon sets features that you get with Excel 2007, but you can achieve the same results using conditional formatting. To make space for our KPI, right click in the right most column of the table, select Insert -> Column to the Right. Using the quick tag selector, choose the <td> tag. In the Conditional Formatting task pane, select Create ->Apply Formatting…. For the condition, select “Stock Greater Than 20” and click ok. You will then be presented with the modify style dialog. Here you can change just about any style aspect you choose, but for now select Background for the category and then set the Background Color to be green. Repeat the same steps three more times: first with the condition “Stock Less than or Equal to 20 and Stock Greater than 10” with the background color yellow, then with the condition “Stock Less than or Equal to 10 and Stock Greater Than 0” with the background color red, and finally with the condition “Stock Equals 0” and the background color black. The reason we had to use both the “less than or equal to” condition and the “Greater than” condition is that each rule is interpreted independently. Because of that, if we didn’t select “less than or equal to” for the second condition then an item that had 50 items in stock would match both the first and second conditions (since it is greater than 20 and greater than 10). Be careful of this when selecting your condition criteria.  You can use the same technique with images (such as a set of up, down, and sideways arrow icons) by using the Show and Hide options as appropriate. Conditional Formatting - Under the Covers I won’t get into the intricate details of XSLT here, but it is useful to know that the way that SharePoint Designer 2007 implements conditional formatting is by wrapping your element with an <xsl:if> clause. The Show option is essentially a clause that says <xsl:if test=”your condition”>your markup</xsl:if>. When the condition is true, your markup shows up in the page. The Hide option is basically the same, but with your condition surrounded by “not()”. You can use the same concepts to create very advanced formatting options by hand if you choose, or use the Advanced… button in the Condition Criteria dialog to use SharePoint Designer’s XPath Expression builder to build your condition. I hope you find some of this useful – conditional formatting is extremely powerful. Enjoy!
| |
|