Andrew Connell [MVP SharePoint]
1741 Posts |  46 Articles |  5310 Comments
.NET  |  MCMS  |  SharePoint  |  Office System
Andrew Connell's RSS Feed    
AC's Blog Quick Links
SharePoint Quick Links
Article Categories
Archives
May, 2012 (3)
April, 2012 (4)
March, 2012 (4)
February, 2012 (4)
January, 2012 (12)
December, 2011 (6)
November, 2011 (3)
October, 2011 (17)
September, 2011 (8)
August, 2011 (6)
July, 2011 (7)
June, 2011 (13)
May, 2011 (9)
April, 2011 (15)
March, 2011 (1)
February, 2011 (6)
January, 2011 (5)
December, 2010 (11)
November, 2010 (6)
October, 2010 (12)
September, 2010 (5)
August, 2010 (4)
July, 2010 (5)
June, 2010 (6)
May, 2010 (11)
April, 2010 (11)
March, 2010 (9)
February, 2010 (9)
January, 2010 (3)
December, 2009 (10)
November, 2009 (15)
October, 2009 (15)
September, 2009 (7)
August, 2009 (4)
July, 2009 (10)
June, 2009 (8)
May, 2009 (2)
April, 2009 (9)
March, 2009 (6)
February, 2009 (16)
January, 2009 (6)
December, 2008 (12)
November, 2008 (12)
October, 2008 (27)
September, 2008 (13)
August, 2008 (14)
July, 2008 (14)
June, 2008 (12)
May, 2008 (23)
April, 2008 (12)
March, 2008 (15)
February, 2008 (13)
January, 2008 (12)
December, 2007 (10)
November, 2007 (8)
October, 2007 (15)
September, 2007 (20)
August, 2007 (21)
July, 2007 (16)
June, 2007 (8)
May, 2007 (25)
April, 2007 (16)
March, 2007 (18)
February, 2007 (18)
January, 2007 (12)
December, 2006 (16)
November, 2006 (13)
October, 2006 (18)
September, 2006 (22)
August, 2006 (27)
July, 2006 (23)
June, 2006 (23)
May, 2006 (23)
April, 2006 (9)
March, 2006 (17)
February, 2006 (15)
January, 2006 (23)
December, 2005 (31)
November, 2005 (32)
October, 2005 (38)
September, 2005 (53)
August, 2005 (30)
July, 2005 (63)
June, 2005 (30)
May, 2005 (59)
April, 2005 (29)
March, 2005 (74)
February, 2005 (27)
January, 2005 (22)
December, 2004 (32)
November, 2004 (42)
October, 2004 (39)
September, 2004 (20)
August, 2004 (14)
July, 2004 (27)
June, 2004 (40)
May, 2004 (5)
April, 2004 (6)
March, 2004 (16)
February, 2004 (26)
January, 2004 (23)
December, 2003 (7)
November, 2003 (14)
October, 2003 (20)
September, 2003 (4)
Post Categories



Managed Windows Shared Hosting

In my previous post I talked about how you implement the events when a user clicks on a button or other control in the ribbon. There are two options available to you in implementing these controls: a more declarative option using <CommandUIHandler /> (SDK link) elements in the Feature element manifests or using a page component. I covered the <CommandUIHandler /> option in the last post. The other option, page components, is covered here.

What is a Page Component?

A page component is a client-side object that tells the ribbon on the page which commands it can handle. This object needs to be added to the page and is not directly coupled with the ribbon UX customizations. This is what tripped me up. I couldn't figure out how to get the page component "registered." It actually was a lot more straightforward than I thought it would be. Once the script is added to the page, you add some commands that create a new instance of the page component and register it with the ribbon on the page.

Why Use a Page Component?

As you'll quickly see, creating a page component requires more work than the alternative. However, there are times when you'll want to create a page component. First of all, and probably the most important, anything that needs to be implemented with a ton of script will be hard to maintain in the XML file.

The second reason is because the page component is an actual client object, you have all the power of an object such as private methods and fields if you need to store state.

Building a Page Component

Building a page component can be broken down into to a few steps once you've written the UX customization pieces (the stuff that creates tabs/groups/buttons):

  1. Build the page component
  2. Make sure any script dependencies your page component needs are on the page
  3. Add the page component to the page
  4. Initialize the page component

The command I walk through in this post is the page component equivalent to the declarative one I blogged about previously.

The first thing you need to do is create a new script file and add something will register the object on the page.

Next, write a few methods that will act as the helpers for setting up the component.

OK, now its time to create the page component‘

Now, create the initialization portion of the page component. This method, init(), will do a few things. I want my page component to respond to a specific command called ApplyDocumentPrefix.OnApplyDocPrefixPageComponent. The way I'm doing this is I'm adding it to an array and wiring up that name with a method in my page component named onApplyDocPrefixPageComponent(). I'm going to do the same thing that will be called to check to see if the command is available. The SharePoint SDK talks about a few other ways of doing this, but I prefer this option:

Two more parts of page component are the getFocusedCommands() and getGlobalCommands() methods. I'll cover these in a later post, but for now my command will be a global command.

So now you need to implement the two methods that check to see if the command is available (canHandleCommand()) and the one that handles the commands (handleCommand()). These use the array I created earlier and call the associated methods:

Now, implement the methods that do the work of handling the command and if the command is available. I'll spare you the one the checks if it is available.

Last but certainly not least is the piece that actually initializes and registers the page component with the ribbon on the page:

Here's a link to the complete *.JS file if you're having trouble looking at pictures.

Implementing a Page Component

So now that you've built this JavaScript object, how are you supposed to get it on the page? There are a few different options an it really depends where your ribbon customizations are located. In any case, you're likely going to want to add it from code. If you're doing it from an application page, site page or a Web Part you're going to do it the same way.

First you get a reference to the ribbon on the page and then make sure all the necessary scripts have been loaded before you add your page component (as there are dependencies in it). Then you add the page component to the page.

The following figure shows how I did this with a page component that added buttons to the Document tab when users are in the document library. It is in a server control that I registered on all pages in a particular site by adding the server control to the AdditionalPageHead placeholder control:

Once the page component has been added to the page, it will run the init statements in the script file that load create a instance of the page component and register it with the ribbon on the page.

I prefer Page Components

Sure, there's a lot more work, but I like the page component option a lot more. Why? I just don't feel right putting my script in XML files. I find it easier to manage the script in a separate file. A side benefit here is that the external library can be cached downstream, but that isn't really a reason I like it because it's such a small file usually.

While there's a lot more script to write, I do like the added control the page component gives me. Your page component can receive focus and only respond to events when it is focused (more on this in another post).

Not only do I prefer them, but in my informal survey, three of four doctors do as well.

posted on Monday, October 11, 2010 7:58 PM

Feedback

# re: Implementing Page Components in the SharePoint Ribbon 6/30/2011 3:48 PM russell
Gravatar Hey Andrew,
Thanks for the wbcast on customizing the sharepoiont Ribbon.
I have a question with yourr demo code. It seems to only work on a root web.

In the CommandAction javascrupt you created the dilog options like this:
var dialogOptions = {
url: '/_layouts/Gerald.MultifileDonload/MultifileDownload.ashx?Item=' +selectedItemIds +'&amp;List=' +SP.ListOperation.Selection.getSelectedList(),
title: 'Download Zip File',
allowMaximize: false,
showClose: false,
width:500,
height:400,
dialogReturnValueCallback: dialogCallback
};

That cuases the conrtext in my layouts page to be the root web, not my subsite,

I tried relllacting the url with
url: '~site/_layouts/Gerald.MultifileDonload/MultifileDownload.ashx?Item=' +selectedItemIds +'&amp;List=' +SP.ListOperation.Selection.getSelectedList(),

but that didnts work. How do I get my layouts page to run in the context of my subsite?


# re: Implementing Page Components in the SharePoint Ribbon 8/9/2011 1:26 PM Paul
Gravatar Andrew,

I've just created a solution that uses a CustomAction

<CustomAction Id="RegisterScripts" Location="ScriptLink" ScriptSrc="~site/_layouts/myproject/myJS.js"/>

that I've placed above the CustomAction that contains my ribbon button and my code is able to call the JS file functions from within the CommandUIHandler's CommandAction and EnabledScript.

Is there a reason not to do this instead of using a page component?

# re: Implementing Page Components in the SharePoint Ribbon 8/10/2011 10:39 PM AC [MVP SharePoint]
Gravatar @Paul - Does it work, sure. Why not do it? Because you are adding additional JS code to every page depending on the scope of the Feature when you might not need it on the page. Basically, this IMHO is the lazy way of doing it but not the correct way of doing it.

# re: Implementing Page Components in the SharePoint Ribbon 8/30/2011 3:31 PM Bart McDonough
Gravatar There's a slight JavaScript issue with the implementation that's presented here. Specifically, it's in the handleCommand and canHandleCommand functions.

In the code above, the functions stored in the arrays are being called like this:

this.handledCommands[commandID](commandID, properties, sequence);

The problem arises when the function being called lives within the page component and tries to use the 'this' pointer to access the page component's member variables. (One example of why that might be done is found here: blog.mastykarz.nl/sample-code-asynchronously-ch...) The 'this' pointer will not be pointing at the page component object like you might expect, even though the function is defined inside of it.

To fix the issue, the function calls can be modified as follows:

// For handleCommand
var fn = this.handledCommands[commandID];
return fn.apply(this, [commandID, properties, sequence]);

// For canHandleCommand
if (canHandle) {
var fn = this.canHandledCommands[commandID];
return fn.call(this);
}

In both of these instances, the page component (referenced using 'this') is explicitly passed to the functions as their context, allowing the 'this' keyword to continue referencing the page component within the function.

# re: Implementing Page Components in the SharePoint Ribbon 9/9/2011 12:26 PM Paul
Gravatar Andrew,

I realized that was an issue and refactored because I still thought the page component was overcomplicating things a bit, at least in the case of my current project.

I do dynamic loading of the js file from EnabledScript and CommandAction attribs. (Thanks to your post here for making me realize the right way to do it: www.andrewconnell.com/blog/archive/2010/10/14.aspx )

Here's the solution I came up:
sharepointers.blogspot.com/.../...stom-ribbon.html

Post Feedback

Title:
Name:
Email:
(email will not be displayed)
Url:
Comments: 
Please add 3 and 7 and type the answer here:    
All Comments Are Filtered & Moderated
Unfortunately comment spammers are just too effecient and are constantly dirtying up blogs with irrelevant and unwanted comments trying to improve their standing on search engines. All comments on this blog are moderated. I do not censor comments, but I don't approve comments with vulger language or those soliciting products. Most of the time comments are approved within a few hours of being submitted with the only exception when I'm traveling.

Why are you asking for my email address?
The only reason I'm asking for your email address, which isn't required to submit a comment, is to provide a gravatar if you've created an account for yourself and associated your email address with a small image. If you have a gravatar created for the email address you submit, it will appear next to your comment. Otherwise nothing will appear.

What is a gravatar?
A gravatar is a "globally recognized avatar." You can get more information about gravatars, as well as create your own for free, at www.gravatar.com. You can also view my gravatar here.


Copyright © 2003 - 2012 Andrew Connell
Creative Commons License 
This work is licensed under a Creative Commons License

 
SharePoint Training
Looking for SharePoint 2010 training for developers, administrators, power users, information workers, end users & web designers? Look no further! My company, Critical Path Training offers the best SharePoint training around! We offer public & private classes both as in-person instructor-loed hands-on classes and online classes. Check out our schedule and course catalog for all the ways we can get you going on your SharePoint path!