SharePoint 2010

Hero Blog Post of the Day

I was working on a project today where I need to dynamically create a MS Word Document, save it to a SharePoint library, and then present the document to the user for editing.  My first attempt was to create an IFrame that would redirect to the document once it was created, but this would only open the document in ‘Read Only’ Mode.

Enter the Hero Blog Post

After a quick search I found this blog post.  DotNetNinja found a javascript function editDocumentWithProgID2 which performs this exact operation and is part of the SharePoint 2010 Core.js file.

Simple!

Advertisements

More About Managed Metadata

I recently had more fun with setting Managed Metadata values in SharePoint 2010.  This time as part of an event receiver during the Item Adding, Item Updating, and Item Updated events.  (There are interesting event ordering challenges which lead to using all of these events, but that is not the focus of this blog.)  The challenge I faced was copying values from a Document Set down to documents that were being created/uploaded to the list.  Normally, using Shared Properties would negate this but because we wanted use to edit the Managed Metadata Values in the Document Information Panel we could not use shared values because the Document Set would immediately overwrite any changes made to the document.  Instead we created an Event Receiver to manually handle the updates from the Document to the Document Set, and from the Document Set to the child documents.

The issue arose that copying the Document Set values to the Document didn’t work.  In the logging we could see our Set function get called and return success, but the values never seemed to stick.  I was using code I’ve previously blogged about:

SPField mmdField = spListItem.Fields.GetFieldByInternalName(“MyMMDField”);
string validMMDString  = mmdField.GetValidatedString(spListItem[“MyMMDField”]);
newSpListItem[“MyMMDField”] = validMMDString;

Since logging was unable to provide enough information I began testing using PowerShell.  Which looked something like:

$field = $listItem.Fields.GetFieldByInternalName(“MyMMDField”)
$validString = $field.GetValidatedString($listItem[“MyMMDField”])
$newListItem[“MyMMDField”] = $validString
$newListItem[“MyMMDField”].ToString()
>> ouput the same as the $validString
$newListItem.Update()
$newListItem[“MyMMDField”].ToString()
>> [Empty]

Interesting, before the Update() my value is there but after I loose the value.  After looking around a bit I ran across this blog, and although it was about using the web services it provides a key piece of information: Managed Metadata Fields have a Lookup Field AND a Note field.  I began exploring the various fields, again through PowerShell, and was able to identify the Note field associated with my Managed Metadata Column.  This value looks almost identical to what is in the Managed Metadata Field but does not include the WSSID.

Example:

Taxonomy Field:
123;#My Term|00000000-0000-0000-0000-000000000000;#124;#My Other Term|00000000-0000-0000-0000-000000000001

Note Field:
My Term|00000000-0000-0000-0000-000000000000;My Other Term|00000000-0000-0000-0000-000000000001

At first it appeared at the Managed Metadata Note Column’s Internal name was the Managed Metadata Column’s Column GUID with the ‘-‘s removed.  That worked great for 2 of my 3 fields, but one field didn’t use that same pattern.  Using PowerShell I printed the Managed Metadata Field Definition to the console and discovered a key property: TextField.  This field is a GUID that stores the (MSDN Article Here) Note Field’s GUID and allows you to get the Manage Metadata’s associated Note field.

Finally, once I began setting both the Managed Metadata Field AND the Note field all of my Managed Metadata values would successfully populate.

Final Code
Note: I did not include checks to ensure cast of the field to Taxonomy Field was successful and I’m also assuming that spListItem and newSPListItem share the same columns.

SPField mmdField = spListItem.Fields.GetFieldByInternalName(“MyMMDField”);
TaxonomyField taxField = mmdField as TaxonomyField;

string validMMDString  = mmdField.GetValidatedString(spListItem[“MyMMDField”]);
string mmdNoteString = spListItem[taxField.TextField].ToString();

newSpListItem[“MyMMDField”] = validMMDString;
newSpListItem[taxField.TextField] = mmdNoteString;
newSpListItem.Update();

Setting Managed Metadata

I recently had an issue trying to set the Managed Metadata field value on a new list item I was creating in C# code.  In the control where the user could select the managed metadata value I was using the OTB Taxonomy Control which was properly bound to my Managed Metadata Field.  From that I would then retrieve the ‘Value’ (Label|Guid) of the Term selected and call the TaxonomyFieldValue PopulateFromLabelGuidPair.  This would successfully retrieve a TaxonomyFieldValue and I would this use this as follows:

TaxonomyFieldValue mmdFieldValue = new TaxonomyFieldValue(string.Empty);
mmdFieldValue.PopulateFromLabelGuidPair(mmdFieldControl.value);
item[field.Id] = mmdFieldValue;

No exceptions were thrown, but when reviewing the list item the Managed Metadata Value was not present. I added the following lines to determine what value was actually in my mmdFieldValue variable being used to set the item’s field:

string validatedString = field.GetValidatedString(mmdFieldValue);
string validatedString2 = field.GetValidatedString(mmdFieldValue.ToString());
string justString = mmdFieldValue.ToString();

What I noticed was the validatedString2 was usually an Empty string, while the validatedString was populated, but included a leading integer. The justString usually had a value of [Label]|[GUID], as expected.

With some experimenting what I found was the validatedString, no matter what value I selected for the field always had the SAME leading integer ‘0’. This was the key to resolving the issue, and what I found was the TaxonomyFieldValue object has three properties: Label, GUID, and WssID.  The WssID was the key, it’s value was also always 0 so I tried changing it to a -1 and suddenly all my Taxonomy Values worked.

Final Code:

TaxonomyFieldValue mmdFieldValue = new TaxonomyFieldValue(string.Empty);
mmdFieldValue.PopulateFromLabelGuidPair(mmdFieldControl.value);
mmdFieldValue.WssId = -1;
item[field.Id] = mmdFieldValue;

Fixing IE11 Enter Key Problem with Search

I was recently working for a client who began having issues with the Windows 8.1 baseline and their search center.  If you are familiar with Windows 8.1 then you are aware that it comes with IE 11 which has a new User Agent string that can cause some issues with SharePoint (ref: IE11 Broke SharePoint 2010).  My task was to figure out why when a user entered a search term/key word and hit enter the page simply refreshed.

I tried several ideas, including attaching to the form submit action, to no success so I began searching the web for any other possibilities I had not though of.  Interestingly, I began running across several similar issues with Firefox from back in the SharePoint 2007 days.  After doing a little reading I began experimenting using IE11’s developer tools and found it has a similar issue to Firefox from years ago.  Here is the problem:

SharePoint’s Keyword Input has a function that does the following check

if(event1.which == 10 || event1.which == 13) { …<submit the form>; return false; }

The problem is that IE 11, when the IE-8 Compatibility Meta Tag is present on the page, returns undefined for the event1.which and therefor our submit function is never called.  Several people had this same issue with Firefox and there were lots of examples on how to resolve, but most required you hard coded the <submit the form> function name, which may or may not be consistent from site to site or even page to page.

I wanted something a bit more dynamic, and what I realized was if I grabbed the Submit function from the actual search button I could just call it directly.  In addition, rather than adding another chained function to the keypress DOM event, which could be bypassed if the event was canceled, I wanted to override the current function with my own definition.

Here is the resulting code I have used which works in IE 11, Firefox 27.0.1, and Chrome 33.0.1750.154:

function ensureReturn()
{
var jsFunction = $(“input[name=’InputKeywords’]”).attr(“onkeypress”);
var jsSplit = jsFunction.split(‘ ‘);
var funcName = jsSplit[jsSplit.length-1].split(‘(‘)[0];

jsFunction = $(“a[title=’Search’]”).attr(“href”);
jsSplit = jsFunction.split(‘:’);
var submitFuncName = jsSplit[jsSplit.length-1];

var newFunc = funcName + ” = function(event) { if(event.keyCode == 10 || event.keyCode == 13) { ” + submitFuncName + “; try { event.cancelBubble = true; } catch(e){} return false; } };”
//newFunc should be something like:
//function SFBE88B03_OSBEK(event1) { if(event1.keyCode == 10 || event1.keyCode == 13) { SFBE88B03_Submit(); try { event1.cancelBubble = true; } catch(e){} return false; } }
eval(newFunc);
}
_spBodyOnLoadFunctionNames.push(“ensureReturn”);

Once that was placed in a JavaScript file and included on the search and results pages the enter key began working again.

IE11 Broke SharePoint 2010

I’ve been noticing recently my SharePoint site was behaving oddly, especially when I wanted to edit a web part. Yesterday the odd behavior hit a critical point as I was unable to connect web parts on a page. The problem was every time I clicked the drop down arrow on the web part heading the page would refresh and some of the menu content would appear in a side panel, where the web part properties are usually displayed.

Knowing we had a customized master page I was convinced some change must have caused the problem. However, after reverting the master page to the site default the problem persisted. A coworker jokingly suggested I try using Chrome or Firefox. In frustration I opened the site in Firefox and amazingly everything worked.

I went back to IE 11 and opened the emulator setting. Although the browser mode was IE8 I noticed the User Agent setting was Default. I decided to change this to the IE8 User Agent setting and after the page refreshed, the site worked as expected.

After doing a little web search I found the IE team’s blog about changes to the User Agent string, which recommends you not use the User Agent Browser Sniffing technique (maybe something to tell the SharePoint Team?).

Overall, the site’s end user experience look unchanged, but it does effect the developer’s and site owner’s experience.

Site Collection Content Type vs. Content Type Hub

I’ve been working on a project recently that has a large number of sub-agencies and the parent organization was attempting to push a standardization of Content Types.  Since no one really wanted to duplicate work the organization decided they did not want to migrate content into SharePoint (from file shares) until all the content types and metadata had been identified and created.  However, as with all large agencies some groups wanted to move forward with limited or partial capabilities because after all some limited capability is better than what they currently have.  The concern that arose from this was: What if they created a Content Type in one of their Site Collections that had the same name as one that would be published later on?

The process I followed was very simple:

  1. Create a new Site Collection
  2. Create a Content Type ‘RFP’
  3. Create a Content Type in the Metadata Hub name ‘RFP’
  4. Publish and see what happens

Once the import of the Content Types was completed I checked my Content Type Import Log in the Site Collection (created in #1 above).  What I found was an error stating: Content Type Name ‘RFP’ conflict.  In addition I checked my Site Content Type and found that the one custom field I had added in the Metadata Hub was NOT included as a field of my local ‘RFP’ Content Type.

SharePoint Published Content Types

I have done a lot of development with SharePoint workflows, especially those developed in Visual Studio.  Unless I have been working with a standard list type, I generally create a Content Type that my workflow can be associated with and to ensure the columns and values needed in the workflow will be present.  However, creating Content Types is always a painful process, because as you develop the content types and test them you need to delete the original content type, and any list depended up in before you deploy the updated version.  This is even worse when you upgrade a solution that is in use in production because you can’t easily delete the content type just to add additional fields.

Recently, I have been working with Publishing Content Types, usually designed through the SharePoint UI, and what I began to notice was that when the published Content Type was updated in the Content Type Hub those changes were reflected in the sites making use of those Content Types.

This made me wonder if the same would happen if I deployed the Content Type through a Visual Studio solution, published it and then updated the Content Type.  I initially created a Content Type that had a Title and a Choice column.  Once deployed I published the content type and created a list in my Published Content Type Consumer site.  I then added an additional text column to the Content Type and redeployed.  After the Content Type Hub timer jobs executed the List I created using the Published Content Type now had the new column.

Lesson from this: If you have to deploy and maintain Custom Content Types use a Content Type Publishing Hub to manage the Content Types, and any future updates you may need to make.