- RCWP Part 1 – Extending the Search Core Results Web Part
- RCWP Part 2 – Web Part with Ribbon Contextual-Tab
- RCWP Part 3 – Edit Web Part using a Ribbon modal dialog
This post summarised the final part of this Web Part (which we completed in the final session of the day of SPRetreat last Saturday).
We wanted to provide a pop-up window, accessed through our new Contextual Tab in the Ribbon, which allowed us to easily modify some web part properties.The basis of this was quite straight-forward, and it certainly starts off quite easy.
We created a new Application Page (RCWP_SetFieldValue.aspx) which would contain the code to update our Web Part Properties.
In this file we added a simple ASP.Net Label, Drop Down List and button.
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">Back in Part 2 we created a JavaScript file which was use for the “Command” events for our Buttons (yes .. I told you we’d be looking at that again!).
<p>
This allows you to set the field value for the <strong>Related Content Web Part</strong>
</p>
<asp:Label runat="server" ID="lblChoice" Text="Select Field:" AssociatedControlID="ddlFields" /><br />
<asp:DropDownList runat="server" ID="ddlFields" /><br />
<asp:Button runat="server" ID="btnNike" Text="Just Do It!" />
</asp:Content>
Here we are going to modify one of the Buttons so that it throws up a SharePoint Modal Dialog with our Application Page in it.
The code below is modified from the original MS Blog Article I referenced in Part 2 (called “How to create a Web Part with a Contextual Tab”).
if (commandId === 'CustomContextualTab.GoodbyeWorldCommand') {I have basically changed the JavaScript for the “GoodbyeWorldCommand” button so that it does something different.
//alert('Good-bye, world!');
var options = {
url: '/_layouts/SPR3/RCWP_SetFieldValue.aspx,
title: 'Set Field',
allowMaximize: false,
showClose: true,
width: 800,
height: 600
};
SP.UI.ModalDialog.showModalDialog(options);
}
I am using the new SP.UI.ModalDialog namespace in the SharePoint ECMAScript to pop up a modal dialog window.
(Note - I also changed the display text to “Set Field” .. and deleted the other button to clean up the ribbon a bit)
But don’t forget that our Application Page is running from _layouts … it’s in a completely different place to our Web Part so this really isn’t enough for our page to work. In order to do anything else our Layouts page would need the following information:
- The Page that the web part is on (URL)
- Which Web Part to update on that page (Web Part ID)
How do you get the server-side Web Part ID through JavaScript?This problem took the entire final hour of the day (Session 5) and took quite a bit of research and web searching. Eventually (after a few suggestions) we hit upon the answer:
Back in Part 2 we created a JavaScript file which was used to register our Contextual Tab. The JavaScript file that registers the Contextual Tab contains a reference to a “PageComponentId”.
getId: function ContextualTabWebPart_CustomPageComponent$getId() {Thes pecific instance of our Web Part had a “PageComponentID” of “WebPartWPQ2” and after some digging we found it in the Source of the page!
return this._webPartPageComponentId;
}
<div WebPartID="866ef42d-6626-45e0-af9c-a00467ed2666" WebPartID2="1ad9529a-5e86-4e7c-9d4d-022a1fa6e6c0" HasPers="false" id="WebPartWPQ2" width="100%" class="ms-WPBody noindex ms-wpContentDivSpace" allowRemove="false" allowDelete="false" style="" >The attribute that REALLY stands out though is the WebPartID:
WebPartID="866ef42d-6626-45e0-af9c-a00467ed2666"This is clearly a GUID value, referring to the server-side Web Part ID for that instance of the Web Part.
So .. how do we get this to our dialog.. well, good old trusty document.GetElementById() (we could have used JQuery, but I didn’t want to have to install the framework .. and don’t forget .. I only had 1 hour to get this working at SPRetreat!!)
Using this information, I could modify my JavaScript to retrieve these values, and pass them through to my Modal Dialog.
// get the Web Part DIV elementNote – as the Web Part ID is of type HTML Attribute, we need to use the “NodeValue” property instead of toString();
var element = document.getElementById(this._webPartPageComponentId);
// extract the Web Part ID (as a GUID object)
var wpID = element.attributes["WebPartId"];
// pass through the URL and Web Part ID
var options = {
url: '/_layouts/SPR3/RCWP_SetFieldValue.aspx?wpID=' + wpID.nodeValue + '&url=' + location.href,
title: 'Set Field',
allowMaximize: false,
showClose: true,
width: 800,
height: 600
};
SP.UI.ModalDialog.showModalDialog(options);
So .. first off, in our Application Page we can use the URL to retrieve the fields from the page’s Content Type and populate our Drop Down List.
protected void Page_Load(object sender, EventArgs e)I did a bit of string manipulation on the URL to make sure we trim out any URL query strings, and then use that to retrieve an SPFile object.
{
TargetUrl = Request.QueryString["url"];
// remove any query strings
if (TargetUrl.IndexOf("?") != -1)
{
TargetUrl = TargetUrl.Substring(0, TargetUrl.IndexOf("?"));
}
if (!Page.IsPostBack)
{
ddlFields.Items.Clear();
SPFile file = this.Web.GetFile(TargetUrl);
foreach (SPField field in file.Item.Fields)
{
if (!field.Hidden)
{
ListItem item = new ListItem(field.Title, field.StaticName);
ddlFields.Items.Add(item);
}
}
}
btnNike.Click += new EventHandler(btnNike_Click);
}
We then just iterate through the SPListItem.Fields collection, adding any fields that are not hidden.
Note – we are using an ASP.Net ListItem object in the Drop Down List, so that we can use the Display Name in the drop-down, but store the Static Name as the value .. it’s the Static Name we need to save to our Web Part!
The next bit is under our Click event. We can now use the URL to get the SPLimitedWebPartManager for the page, and pass through the Web Part ID property, and it would retrieve the instance of my Web Part (allowing me to set the field value).
protected void btnNike_Click(object sender, EventArgs e)So .. we should be done…
{
// get Web Part ID
wpID = Request.QueryString["wpID"];
// retrieve the Web Part Panager for the URL
SPFile file = this.Web.GetFile(TargetUrl);
SPLimitedWebPartManager wpm = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
// get the safely-casted web part object
RelatedContentWebPart.RelatedContentWebPart wp =
wpm.WebParts[new Guid(wpID)] as RelatedContentWebPart.RelatedContentWebPart;
if (wp != null)
{
// set the web part property, and save settings
wp.FieldName = ddlFields.SelectedValue;
wpm.SaveChanges(wp);
}
// close the modal dialog
this.Context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");
this.Context.Response.End();
}
Build / Deploy / Test
So .. a long journey but worth it, five different 1 hour sessions and a great day at #SPRetreat .. but definitely worthwhile, and a new “Related Content Web Part” to boot!
A massive thanks to Andrew Woodward (21Apps) and Ben Robb (CScape) for organising the event, the venue and the food! (great food!!!)
Source Code
Sorry it took so long for me to get it all online, I was very busy then went on holiday. You can find all of the source code downloadable from my SkyDrive here:
http://cid-60f12a60288e5607.office.live.com/self.aspx/SPRetreat/SPR3.zip
Martin,
ReplyDeleteWondering when the source code may be available online....thanks
regards
Julian
Yeh sorry about that.
ReplyDeleteTook ages (slipped my mind, then lots of client work followed by summer holiday).
Up now though! cheers
Hello,
ReplyDeleteThis is really interesting take on the concept. I never thought of it that way. I came across this site recently which I think it will be a great use of new ideas and informations.
Extract Web
Hi,
ReplyDeleteI have succesfully deployed your wsp package and its working for me. But when i add it as a webpart, I can see the results page but refinement panel is not working with it. it works fine when i do the regular Search core result webpart but not with Related Content webpart. I even tried connections but gets message saying "No Schema". please let me know if you have any ideas. Thanks
Anon,
DeleteThis is a custom web part for a specific purpose, showing a simple set of results which are related to the current page.
I haven't checked but it was never the intention to get this working with other search features such as Refinement Panels.
The source code is available for download, so by all means look through it and use it / customise it for your needs
Hi,
ReplyDeleteI was able to try contextual tab for the webpart, but when i added another instance of the same webpart into same page, contextual tab button works only for the first instance. For the second instance tab is available but the button in the ribbon tab is not enabled.
Hi Martin
ReplyDeleteThe download link doesn't seem to be working??
Thanks
Martin
Martin,
ReplyDeleteWorked for me .. what error are you getting?