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

AngularJS Module for Azure Mobile Services

A few months back a coworker introduced me to AngularJS as an alternative to using KnockoutJS.  Around the same time Microsoft was pushing a bunch of videos and “How To’s” on the Azure Mobile Services.  After walking through the AngularJS tutorial and playing with the Azure Mobile Services “To Do” Demo I decided it would be interesting to mesh these two items together, use AngularJS in the UI to communicate with Azure Mobile Services for data storage, and who know what else in the future.

The first thing I did was create the To Do demo application and then I started to create the AngularJS partial views for everything.  Once the views and all worked I began working on the actual communication with the Azure Mobile Services, and this is where things went south.

Don’t Assume AngularJS Behaves

So the major problem I ran into was that I *ahem* Assumed that AngularJS would behave with JQuery Deferred objects, in particular with the Ajax objects and the ‘Then’ chaining.  I know AngularJS has its own Ajax methods, but the Azure Mobile Services utilize JQuery and I wanted to stick as close to the “To Do” code as I could.  Well, what I found was AngularJS doesn’t behave well with JQuery Then chaining, and this has to do with Angular’s $q object.  If you read the documentation for $q you will find, somewhat glossed over I believe, the following statement in the section “Differences between Kris Kowal’s Q and $q” the following statement:

$q is integrated with the $rootScope.Scope Scope model observation mechanism in angular, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repains, which would result in flickering UI.

The first part of that statement is key: $q is integrated with the $rootScope.Scope which means other deferred objects that change values linked to UI components won’t trigger the $rootScope.Scope to repaint the browser display.  Therefore code like:

$get([some url]).then(function() { someUiBoundVariable = "in then"; });

would fail to update the UI with the “in then” string value.

Solution

So after realizing the issues of $q Deferred objects vs. other JavaScript Library Deferred objects I rewrote my Azure Service to utilize the $q deferred object.  Interestingly, my coworker who introduced me to AngularJS soon contacted me about how to integrate AngularJS with the Azure Mobile Service, so I took my object and made it more generic so he and I could both use the same AngularJS Module.  After we both used this for a little we realized we had a reasonably solid AngularJS Module for the Azure Mobile Services, and so was born the AngularJS Module for Azure Mobile Services NuGet Package and AngularJS Module for Azure Mobile Services Codeplex Project.

Get AngularJS Module for Azure Mobile Services

There are two ways you can use the AngularJS Module for Azure Mobile Services.  First you can use NuGet and add AngularJS Module for Azure Mobile Services to your project.

NuGet Package: http://www.nuget.org/packages/AzureMobileAngularServices

Or you can download the js file directly from CodePlex and add this to your project.

CodePlex Project: http://azuremobileangularservices.codeplex.com/

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.

I Hate SharePoint Apps like I Hate Mark Zuckerberg

This blog post has been tumbling in my head since I began working on SharePoint 2013 Apps.  This is probably the third time, at least, I have tried to express my thoughts on the development shifts in SharePoint from 2007 & 2010 to 2013.

Beware some things in this post may be offensive to people, especially Mark Zuckerberg, but I wanted to bring a little humor into the geek speak.

Do I Really Hate SharePoint Apps?

I think hating SharePoint Apps is like hating someone like Mark Zuckerberg for creating Facebook.  I don’t hate him for creating Facebook and making billions, I hate that I didn’t think of creating Facebook first.  I could have created a web site where we share things that should be kept to ourselves.

“… I meet this chick at the bar and we hooked up and now my _____ is all swollen and it burns when I …”,

WOW, I really didn’t need to know that, but oh great you also included a picture!  Because that image won’t be permanently burned into my memory from here until the end of time, THANKS Friend! And now to perform a lobotomy on myself.

Or where adults can act like immature teenagers by unfriending each other (please read with ditsy Valley Girl ‘accent’)

“Suzie unfriended you because your friends with Katie who just started dating Charlie even though she knew that Suzie liked Charlie and wanted to go out with him.”

Yeah, next time you read your Facebook feed I dare you not to think of this post!

But alas, Mark beat me to it.

So no, I don’t hate SharePoint Apps, but there are parts of them I haven’t fallen in love with, or even understand why they work this way instead of that.

Augmenting SharePoint or Bolting On

I was talking with a coworker recently and described my past, and current, experience with SharePoint and described it as “Augmenting SharePoint” either to improve the user experience (custom content types and lists to allow users to collect information consistently), build automation capabilities/processes (workflows that would handle publishing and retiring of content), or use data from other systems to enhance information in SharePoint (KPIs from Project Server along with Task Lists in SharePoint).

As my coworker pointed out, Apps are much less of the augmentation and much more of a bolt on.  Sure, you can borrow some of what SharePoint has in Apps, but your App isn’t going to be used in the same context and location that user created a document library or enabled/disabled features.  Our Apps are isolated, associated with SharePoint, but they aren’t SharePoint just like a Zynga game (or whoever makes your favorite Facebook game) isn’t Facebook and doesn’t change Facebook.

Change of Perspective

When I approached SharePoint Apps with the mindset that I was going to augment what SharePoint gave the user, I found nothing but frustration.  I would think first about what SharePoint could provide: lists for storing data, user security, etc. but I would quickly realize my App expected too much and that there was too little focus on my application.

I have now tried to spin that perspective 180 degrees, thinking first about what I want to build, maybe it as better calendar, and what it should do even without SharePoint.  Then after I knew what my App should do and how I was going to make it work I would think if there was anything I needed from SharePoint.

More customizations with Client Side Rendering

Recently I posted about how you can use Client Side Rendering (CSR) to display contacts on a map.  After posting about how to display the entire list data, I decided I wanted to see how CSR could  be used to change the user experience while adding, updating, and viewing list items, updating items, and viewing items.  This post will provide a high level overview of how I was able to change the display during New, Display, and Edit of an individual item and then later I will actually put this together with the Contact Map idea.

Where’s the Documentation?

As mentioned in the previous blog, this work was all pretty much done 100% in the dark.  I was able to find a few blogs about how to style specific fields, in particular those custom fields being added by a feature, but there really isn’t much about the full CSR capabilities.  In order to figure some of this stuff out I ended up using the IE Developer Tools Console to view various objects, in particular the SPClientTemplates.TemplateManager and SPClientTemplates._defaultTemplates JavaScript objects.

Specific Items mean Specific Field(s)

My original goal was to do something, really anything, with all the input fields.  However, to date, I haven’t been able to figure out how to get my CSR to change all the fields, but I have been able to impact specific field(s) and in the remainder of this post I will focus on impacting my custom field ‘Lat’.  This being said, the CSR does include a OnPostRender function which you can use to ‘go back’ and update the fields, but it doesn’t do anything while the field is being rendered.

CSRs need to self execute, and to prevent namespace pollution I’m using the self wrapping anonymous function.

(function() {
})();

We will again use the overrideCtx and overrideCtx.Templates objects to specify the various items we want to control.

var overrideCtx = {};
overrideCtx.Templates = {};

Unlike our Contacts on a List example this time rather than overriding the Item template we are going to override the Fields.  Fields is a bit different from the item in that rather than providing a function which is passed a context object, Fields is an object that specifies the field(s) we want to override during render.  For each field specified we can then provide our rendering template function which receives the current Field’s context.

overrideCtx.Templates.Fields = {

‘Lat’: {

‘NewForm’: function(ctx) { return (“<div style=’border: 1px solid blue;’>Hello World</div>”); }
‘EditForm’: function(ctx) { return (“<div style=’border: 1px solid green;’>Hello World</div>”); }

}

};

Initially, the names ‘NewForm’ and ‘EditForm’ which match up with the URL /NewForm.aspx and /EditForm.aspx caused me to assume the naming’s should use the name of the ASPX form.  However, ‘DispForm’ (/DispForm.aspx) did not provide the expected rendering and this is where the IE Developer Tools were critical.  Using the IE Developer Tools and the Console I was able to look at the SPClientTemplates._defaultTemplates where I was able to traverse the object structure and found the function ‘DisplayForm’.

Related

SharePoint Contacts on a Map with Client Side Rendering