Firing an Event When a User Selects a Value from a Data View Web Part Dropdown
I was skimming my old postings, and I realized that in a previous post, I had said that I would post about firing an event when a user selects a value from a DVWP dropdown. Better late than never, I guess.
When you create a dropdown type of DVWP through the UI in SharePoint Designer, the dropdown is created just fine, but there is absolutely nothing there to make that dropdown actually *do* anything. Helpful, but not much. Here’s how you can make it worth something.
In this example, my goal was to pass the chosen value to another page through the query string (There are other ways to do this, but for this client, there was auditing software that made having the value in the URL of use.) so that I could display the set of items that were created during a specific archive period. (I had a calculated column that gave the archive period based on the published date — see this post on how that works.)
- Add a DVWP to the page
- Drop the column you want to see onto it
- Change layout and choose the second from the bottom option — Dropdown menu of titles
To get at the query string variable ArchivePeriod (seen in the code below referred to as $ArchivePeriod) you go to the DVWP ‘Common Dataview Tasks’ (click on the little > button to the right on the DVWP), and set up a Parameter as seen in the screen snippet below. If you search the code for the page for ArchivePeriod after doing this, you can see the effect of your actions. You can, in fact, add the variable directly into code, as you see! (There are two lines for ArchivePeriod now.)
The key portions of the code that SharePoint creates when you add this DVWP to the page as in the three steps above are as follows:
<xsl:template name="dvt_1"> ... <select name="ID" size="1"> <option selected="true" value="0">Choose One...</option> <xsl:call-template name="dvt_1.body"> <xsl:with-param name="Rows" select="$Rows" /> <xsl:with-param name="FirstRow" select="1" /> <xsl:with-param name="LastRow" select="$dvt_RowCount" /> </xsl:call-template> </select>
and
<xsl:template name="dvt_1.rowview"> <option> <xsl:value-of select="@Archive_x0020_Period" /> </option> </xsl:template>
While Designer has created a nice dropdown for you, nothing will happen if you make a selection; that work is left to you. Here are the changes that I made; I’ve explained the changes below.
<xsl:template name="dvt_1"> ... <select size="1" onchange="HandleFilterSelection('default.aspx', 'PageFilterArchive.aspx', 'ArchivePeriod', this.options[selectedIndex].value)"> <xsl:choose> <xsl:when test="not(string-length($ArchivePeriod))" > <option value="0">Choose Dates</option> </xsl:when> <xsl:otherwise> <option value="*">All Dates</option> </xsl:otherwise> </xsl:choose> <xsl:call-template name="dvt_1.body"> <xsl:with-param name="Rows" select="$Rows" /> </xsl:call-template> </select> <xsl:template name="dvt_1.rowview"> <xsl:variable name="NewGroup" select="ddwrt:NameChanged(string(@Archive_x0020_Period), 0)" /> <xsl:if test="string-length($NewGroup)"> <option> <xsl:if test="$ArchivePeriod = @Archive_x0020_Period"> <xsl:attribute name="selected"> <xsl:value-of select="selected" /> </xsl:attribute> </xsl:if> <xsl:attribute name="value"> <xsl:value-of select="@Archive_x0020_Period" /> </xsl:attribute> <xsl:value-of select="@Archive_x0020_Period" /> </option> </xsl:if> </xsl:template> function HandleFilterSelection(defaultpath, filterpath, parameter, selection) { if(selection == "*") { document.location.href = defaultpath; } else { document.location.href = filterpath + "?" + parameter + "=" + selection; } }
- Line 3: Adding the onchange event allows you to provide an action if the value in the dropdown changes. I decided to handle this in an externally stored Javascript function called HandleFilterSelection so that I could reuse it easily.
- Lines 4-11: This xsl:choose lets me alter the prompt based on whether there is currently a filter in place or not.
- Lines 18-19: This code lets me test to eliminate duplicate values. This works because I have the list items sorted in descending order by Publish Date.
- Lines 22-24: If the value is the currently selected value (i.e., it is driving the current filter on the page), this code lets me set it as the selection in the dropdown.
- Lines 26-28: Unless you specifically set the value that will be returned for the selection, it’s an unpredictable number. By setting it to the actual text of the selection, we can ensure the it is both recognizable and unique.
UPDATE 2009-05-01 — As a response to Patrick’s question below (It’s hard to include code in a comment.):
In my example, the HandleFilterSelection JavaScript was stored externally from the page because I used it in many places. (I usually create a Document Library in the root site of the Site Collection called JavaScript to store .js files. I then include them in the pages where I want to use them by adding a <script src=”blah.js”> into the page.)
You can have the onchange event for the select do anything you want. For example, I often just call the same page with a Query String parameter, like in the code snippet below:
<select name="SelectFluid" size="1"> <xsl:attribute name="onchange"> document.location = '<xsl:value-of select="$URL"/>' + '?F=' + this.options[selectedIndex].value; </xsl:attribute>
To have this work, declare a parameter in the ParameterBindings section for the URL server variable (see my post entitled Data View Web Part Parameters Based on Server Variables for more on using IIS server variables):
<ParameterBinding Name="URL" Location="ServerVariable(URL)" DefaultValue=""/>
and then declare the parameter at the start of your XSL:
<xsl:stylesheet [...]> <xsl:output method="html" indent="no"/> <xsl:param name="URL"/>
Phil:
I added some text into my post that outlines where the $ArchivePeriod value is coming from and how to access it. I hope this answers your question; let me know if you need any other details.
M.
Marc i just your trick and it looks interesting but anytime i select a drop down i get error “Object Expected..
Where exactly did you hook the js?
In the master page,directly on the page or from a external source linking to a master page
Thanks
Patrick:
I’ve added some more info to the bottom of the post. Let me know if it helps…
M.
This is very helpful. Thanks.
Marc – thanks so much for this, works well for me. The only problem I’ve run into is that the code you provided in lines 22-24 doesn’t work to set the drop-down based on the value driving the current filter on the page. The action works fine, I am taken back to the page with the query string added to the URL and the dataview is filtered accordingly, but my drop-down goes back to displaying “Choose One…” instead of showing the value I’d just selected. Thanks! – Chanda
Chanda:
Make sure that line 21’s xsl:if test contains the Query String parameter and the corresponding column.
M.
Marc – this is great stuff. With the DVWP changed to a drpdwn like this, how would you establish a connection (or implement a connection) to another webpart based on the selection. That is, what if you wanted to filter another web part or alter the contents of another webpart automatically based on the selection?
David:
I generally forego Web Part Connections, as I find they never do exactly what I want. Generally, I simply pass the chosen value back to the same page on the Query String and then have my Data View Web Parts (DVWPs) pick up that value to use it.
Now that I am getting more into SharePoint’s Web Services, I can do quite a lot without needing a roundtrip to the server, however. See http://spservices.codeplex.com/ and my recent posts about it.
M.
Thanks Marc.
So by doing this, as you have done above in the SelectFluid example or with “Archive Period”, I would be able to automatically change another webpart based on the query parameter? I was actually using a cookie instead (since I wanted to hide the parameter).
I checked out the codeplex site. Very cool. I am working completely on the client side without any installations or changes to the server side. Could these still be used in this case?
One of the great things about the jQuery library is that you need to do nothing server-side. In fact, all of your scripting can go into Content Editor Web Parts. (I prefer to embed my scripts in the page using SharePoint Designer.)
In the examples above, you’ll see that a selection fires an event which passes the selected value back to the server on the Query String. Then any controls on the page can pick up those values and use them. You can also use scripting on the client side to act on the values, and I have examples of that in other posts.
M.