Monday, May 30, 2011

Web part functional specifications document template

Hi
Following my last session at the Toronto SharePoint Business user group, here's a link to web part functional specifications document template I've mentioned there.
The purpose of this template is to help SharePoint business analysts to make sure they fully cover all functional aspects when designing a custom developed web part.
Please feel free to comment.
Coming soon: SharePoint site functional specifications template.
Cheers
Nimrod

Setting default value to column in document library

Hi,

One question I hear a lot from developers and system designers is “How can I set a default value to a column in a document library”?

The same goes for form libraries in SharePoint, Apparently SharePoint does not support default values for document libraries.

The first thing that comes to mind, as a solution for this predicament, is to build an event handler that will set a default value to the fields you need whenever a new item (document) is added to the library.

An experienced developer will tell you you should use the ItemAdding event, in order to set the default values to the field during the same update that the user initiated, and under his credentials.

To do that, you will have to use the properties.AfterProperties["FieldName"] = “Default Value”; to set your value.

But – you will be surprised that document libraries, although they do support the ItemAdding event, do not support properties.AfterProperties use. This collection is always empty and ignored in document libraries!

So, the only solution to set a default value to a field in a document library is by using the ItemAdded event.

During this event, the SPListItem was already created and is accessible through properties.ListItem property (unlike ItemAdding, that happens before the item was created).

So, setting the field should be rather easy: properties.ListItem[“FieldName”] = “Default value”;

But you will have to update the file manually yourself, since this happens after SharePoint has already processed the update of the item.

Naturally, you will not want to update the modified date/time, modified by user, and also you will not want to create a new version or emails alerts to be sent out.

So, instead of using the properties.ListItem.Update() method, use these lines of code:

base.DisableEventFiring();
properties.ListItem.SystemUpdate(false);
base.EnableEventFiring();



Or the SharePoint 2010 code equivalent:



this.EventFiringEnabled = false;
properties.ListItem.SystemUpdate(false);
this.EventFiringEnabled = true;


This will allow you to use custom code and programmatically set a default value to any SharePoint library column. Note that the same code should also work for SharePoint Lists, but this is supported through the UI or during the ItemAdding event.



For those of you who are not developers, or would rather a 3rd party solution, you can use KWizCom List Forms Extension solution version 2.1.60 or higher, where you can find a settings page that allows you to set advanced default values using this workaround.



Thanks, Shai.

Tuesday, May 24, 2011

Recruiting senior developers

Hi all,

Just an FYI, KWizCom is recruiting senior SharePoint developers to it’s R&D product development team.

We are looking for skilled and experienced developers in the greater Toronto area.

Your experience:

  • At least 3 years of developing on Microsoft SharePoint platforms. 2010 experience is an advantage
  • required skills: C#, ASP.NET, Javascript, jQuery, AJAX, DHTML, Web services, TFS, XML/CAML
  • nice to have: Silverlight, JSON, XSLT, SharePoint Designer, MS Office, workflow foundation, BDC/BCS/BizTalk, Hyper-V

Your responsibilities:

  • Work within tight delivery dates
  • Work in small, highly professional team
  • Be a part of the product lifecycle, attend brainstorming meetings, have a real impact on the product features and UX
  • Work in a highly creative environment

Although there is a work from home option, you will be required to attend meetings at our office, located at Markham Ontario, so we are looking for local candidates.

If you are up to it and would like to come in for an interview, please email me your CV to shai at kwizcom dot com.

Thanks!

Friday, May 20, 2011

Promoting user profile changes into local site user profile

Here is a problem that I faced more then once, with no proper way to resolve it so far…

User changes his email address or display name in his user profile using his mysite’s profile update page, but the changes are not updated in all the site collections where this user is a member of.

Display name, email settings – nothing!

Online doc’s and research says you can use the “STSADM –o sync” command, but it never helped me in those cases where it didn’t work in the first place.

The only other solution I found was to delete the user from the site collection (which removes all his permissions) and add it again. But this is unacceptable for most users.

Recently I stumbled upon this tool in codeplex by Berry Cohen:
http://userprofilesync.codeplex.com/

while his code was for SharePoint 2007, I needed it on my 2010 machine, so I upgraded it to 2010 and shared the new build in the codeplex page.

I have yet to determine if there are any side effects to using this tool, but so far it seems to be working with no problems!

It actually creates the fields in the user profile list for the site collection, which in turn allows me to even edit and modify it directly there.

Only note is, for production farms – use with caution! (and also, for production farms if you have that problem I would investigate it rather than using a workaround).

I was sorry to hear that Berry’s experience with SharePoint was short, and hope to have you back among our lines soon!

Friday, May 6, 2011

PageComponent code example for SharePoint Ribbon

I get a lot of requests lately to share my example for a simple generic PageComponent JavaScript object (class) that can handle ribbon events.

The was it works is simple, I will probably blog about it in more details later on but in a nutshell there are 3 client side objects that are involved with the ribbon work on the page:

1. PageManager

One object that have a collection of all PageComponent objects for the CommandDispatcher to be able to work with them

2. CommandDispatcher

The only object that handles ribbon events. Any action that happens on the ribbon sends the CommandName of the associated event to the CommandDispatcher. In turn, the CommandDispatcher goes to all available PageComponent objects and ask each one of them if the can handle that command, and if they do – it asks them to handle the command, thus invoking their command handlers.

3. Collection of PageComponent objects

PageComponent object are client side script classes that inherit from CUI.Page.PageComponent (yes, JavaScript class that inherits from a base class!). They declare a collection of CommandName strings of commands they know how to handle and are sometimes associated with a control on the page (web part, field control etc), and when ever such a command is invoked the CommandDispatcher asks them if they can currently handle that command, and if yes – it asks them to handle it. There is no limit to the number of PageComponent objects on the page, or to the number of PageComponent that handles a specific commands. You can also handle commands from OOB ribbon controls, and does not have to be the creator of that ribbon control.
Note: If a command has no PageComponent that can handle it, the control associated with it will be disabled (button, group) except for a tab that does not have to have a command associated with it.

Here is an example of a page component that I start from, feel free to take it and use it, it is very similar to the example available on MSDN with a bit more explanations:

//See documentation in page component: http://msdn.microsoft.com/en-us/library/ff407303.aspx
//TODO: choose namespace like you would in .NET applications. Use company name, project name and module name to avoid conflicts
Type.registerNamespace('Company.Project.Ribbon.PageComponent');

//Create the object
Company.Project.Ribbon.PageComponent = function (PageComponentId) {
this._pageComponentId = PageComponentId;//keep record of associated control (web part, field control, etc..) that is active in this current instance of page component.
//Initializes the base type CUI.Page.PageComponent (Base class is associated through Type.registerClass(Type, BaseType)
Company.Project.Ribbon.PageComponent.initializeBase(this);
}

//Declate it's prototype
Company.Project.Ribbon.PageComponent.prototype =
{
//This will be initialized by caller (web part, field control etc)
_pageComponentId: "PageComponentIDHolder",

getId: function () {
return this._pageComponentId;
},
init: function () {
//Create a list of commands that your page component can handle (JSON string array).
//TODO: edit this collection, these are the command names you wish to handle from the ribbon controls you are listening to.
this._myCommandList = ['Company.Project.Ribbon.PageComponent.CMD1',
'Company.Project.Ribbon.PageComponent.CMD2',
'Company.Project.Ribbon.PageComponent.CMD3'];

//Create an array of methods used to handle commands passed to the page component.
//Use Function.createDelegate to keep current class instance (this) when the method is called.
//TODO: add handler per command in this._myCommandList. Later on - you will have to create the actual script handler method.
this._myHandledCommands = {};
this._myHandledCommands['Company.Project.Ribbon.PageComponent.CMD1'] = Function.createDelegate(this, this.CMD1_Handler);
this._myHandledCommands['Company.Project.Ribbon.PageComponent.CMD2'] = Function.createDelegate(this, this.NotImplemented);
this._myHandledCommands['Company.Project.Ribbon.PageComponent.CMD3'] = Function.createDelegate(this, this.NotImplemented);
},
getFocusedCommands: function () {
return this._myCommandList; //return supported commands collection
},
getGlobalCommands: function () {
return this._myCommandList; //return supported commands collection
},
canHandleCommand: function (commandId) {
//TODO: In our logic, if there is a handler we can handle the command.
//But you might have more logic here, like: if commandId = DeleteItem - can handle only if there is 1 item selected.
var canHandle = this._myHandledCommands[commandId];

if (canHandle)
return true;
else
return false
;
},
handleCommand: function (commandId, properties, sequence) {
//Handle the command - simply getting the command handler (delegate) form the hash table and invoking it.
return this._myHandledCommands[commandId](commandId, properties, sequence);
},
isFocusable: function () {
return true;
},

//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~ CUSTOM PAGE COMPONENT LOGIC STARTS HERE ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
// This is where you should add your custom script hadler methods.
// TODO: Implement each handler in this._myHandledCommands
//

CMD1_Handler: function (commandId, properties, sequence) {
alert("Handling CMD1_Handler");
},
NotImplemented: function (commandId, properties, sequence) {
alert("This command was not implemented yet");
}

//
//
//
//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~ CUSTOM PAGE COMPONENT LOGIC ENDS HERE ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
}

//This makes our object inherit of CUI.Page.PageComponent
Company.Project.Ribbon.PageComponent.registerClass('Company.Project.Ribbon.PageComponent', CUI.Page.PageComponent)
//Execute pending operations waiting for this script to be loaded.
NotifyScriptLoadedAndExecuteWaitingJobs("Company.Project.Ribbon.PageComponent.js");


So, now that we implemented our PageComponent, all we need is to create an instance and register is with the PageManager using this code that makes sure all JS files were fully loaded:



function init2() {
//All JS files were loaded - create instance and register it.
var instance = new Company.Project.Ribbon.PageComponent("ComponentID");
SP.Ribbon.PageManager.get_instance().addPageComponent(instance);
}

function init1() {
//Wait for ribbon JS to load
ExecuteOrDelayUntilScriptLoaded(init2, 'sp.ribbon.js');
}
//Wait for our JS to load
ExecuteOrDelayUntilScriptLoaded(init1, 'Company.Project.Ribbon.PageComponent.js');


I hope this helps you when you are implementing your custom ribbon solutions, or if you need to handle an existing ribbon command in addition to its OOB logic.



Note: to replace an OOB logic of a ribbon command there are other steps you need to take, I will try blogging about it soon as well.



Thanks, Shai.