Client Side People Picker with HTML5 Placeholder text

Lately I have been working with the OfficeDev Patterns & Practices samples a lot. The amount of quality examples provided in that project is amazing, and a huge thanks should go out to all that contributed. One of the components created in the Patterns & Practices is a client side people picker that can be used in Provider Hosted Apps. This component creates a people picker inputbox that closely resembles the one you get in OOTB SharePoint.

In this blog post I’ll guide you through the steps required to extend this component to be able to add a placeholder text that describes what the field’s value should contain, using the HTML5 placeholder attribute. This allows for a much nicer UX, and makes your client side people picker go from this:

peoplepicker4

To this:

peoplepicker2

Before we get down to business, it’s important to note that this post assumes you already have your client side people picker up and running, using the Core.PeoplePicker solution. You can find out how to do just that here.

The first step is to actually include the placeholder text in the input element. That part is relatively easy. The sample dictates a certain HTML structure, because the javascript file is dependent on that structure. You need a surrounding div, span element, input textbox, search area and a hidden field that ends up containing the actual selected people value. This structure is shown below:

In order to add the placeholder text, change the Width of the asp:Textbox to 155 (or a different value based on the length of your placeholder text), and add the attribute placeholder=”your placeholder text”. If you fire up the page, the initial result is exactly what you want. However, if you add a user, you want the placeholder text to disappear, and only adding the placeholder attribute doesn’t do that:

peoplepicker3

The reason it doesn’t hide the placeholder text is because the value for Test User 1 isn’t stored inside the input box, but rather inside the hidden field. And because the input box doesn’t have any value, the default behavior is to show the placeholder text.

In order to fix this, we’ll need to add a change event to the hidden field that stores the people picker value. In case the value is changed, we want to adjust the placeholder attribute on the input field accordingly. And secondly, we need to make sure the change event is fired when a user is added or deleted (default behavior for a hidden field is that value change events do not fire, because it’s not the user that executes the change, but rather the javascript).

To add a change event to the hidden field, you can include the following line of javascript in your $(document).ready function:
$(‘#hdnSiteOwner’).change(changeSiteOwnerPlaceholder);

The function that is executed on the value change is shown below:

It looks at the value for the hidden field. If the value does not equal ‘[]’ (which is the value set by the control in case a user is cleared out), a user has been selected and the placeholder text is emptied. If the value does equal ‘[]’, no user is selected and the placeholder text is restored.

The last step is to make sure the change() method gets executed when a user is selected or removed. To do that, we need to add several lines of code to the peoplepickercontrol.js file. The methods ‘RemoveResolvedUser’, ‘RecipientSelected’ and ‘DeleteProcessedUser’ need to have the following line included at the end:

this.PeoplePickerData.change();

Which makes the methods end up like this:

And that’s it! Now you have a fully functioning client side people picker with a placeholder text that is cleared after a user has been selected, and returns in case all users are cleared. Your end users will certainly appreciate the informative description that you have just added! Happy coding.

Dynamically changing MasterPages in SharePoint 2013 when using Device Channels

Suppose you have a public facing website that has about 40 different page layouts. You are also using the Device Channel functionality, which is new to SharePoint 2013. Basically this means you can set multiple MasterPages, one for each device channel you use. But what if you want to have a different MasterPage for one of the page layouts you use. You have to take into consideration, that when updating the MasterPage from the code behind file, the MasterPage is updated for any and all device channels you use. But what if you only want to change the MasterPage for a certain device channel, but keep the default for all others? That’s where this post comes in.

First let’s take a look at how you can change the MasterPage from the code behind file of a Page Layout. This post by Kirk Evans shows you how to deploy a Page Layout and how to create a code behind file for this Page Layout. This post by Eric Overfield gives us a hint on how to change the Masterpage from the code behind file. As noted, you can only change this property in the OnPreInit method, otherwise the MasterPage will have already loaded and changing the property would result in an error message. MSDN shows the following example:

This would however change the MasterPage for all device channels and remember that we only want to change this MasterPage for a specific device channel. This post advices you to use a HttpContext variable that is called ‘EffectiveDeviceChannel’. The post also warns that this property might not be available everywhere because it is loaded on demand. I have tried to use this property, but unfortunately, as you would have guessed, it was not yet available during the OnPreInit method so I had to find a different solution. Browsing the web didn’t do me any good, and since most of the Mobile classes in SharePoint are sealed, those weren’t of any help either. After inspecting the entire HttpContext, there was one property that I could ‘misuse’ and was the solution to my problem. The HttpContext.Current.Items[‘MasterPageUrl’] was there, and it was showing the URL to the MasterPage that was about to be loaded. Since the device channels all have different Masterpages, this became a solution for me to change the MasterPage only for a specific Page Layout. The code used for this is displayed below:

So, when changing the MasterPage from a Page Layout file when also using Device Channels – resort to using the HttpContext variable MasterPageUrl, because the EffectiveDeviceChannel variable is not yet loaded at that point in the life cycle. Gotcha!

Sequence Dropdown Box using javascript and HTML

Have you ever come across that scenario where you have more than a few input fields and you want to go the user the ability to sort these fields, without having to copy + paste the input several times? In these cases, multiple dropdown boxes next to the input fields specifying the order of these fields can be very useful. This got me thinking, “Well, doesn’t SharePoint already implement something like that, for example when modifying a list view?”. In this post I’ll describe how Microsoft has implemented this and how it can work for you. This example uses only javascript and html, so if you want to do some server side action with it, be sure to modify the code accordingly.

First off, here’s an example of modifying a list view, where you will find these dropdown boxes:

listView

In order to retrieve the code that Microsoft uses for this, I’ve inspected the page and rebuild the same scenario. Here’s the pure HTML that is used:

As you can see, this is nothing fancy. Just a simple HTMLSelect item containing a few options. The onchange method calls a certain Javascript function. This javascript function does all the magic for us, and makes sure that all the other dropdown boxes get their values changed accordingly. The javascript that is used for this is:

The second value specified in this javascript call is the HTMLSelect number of your current item. So for the first dropdownbox, that would be item 0. For the second it would be item 1, etc. The third value is the number of dropdownboxes that are there in total.

So there you have it! A simple HTML and Javascript example of making your website that much more user friendly.

Error calling CreateNewDocumentWithRedirect in IE11 and Chrome

For one of our customers we had to create a custom ‘New Document’ functionality. Since this customer had a lot of different document templates, but all templates have the same fields, the normal way to do this is to create a new content type for each document template. This is due to the fact that there is a one-to-one relationship between a content type and the document template assigned to it. One content type can’t have more than one document template.

Luckily there are some good examples out there on creating a custom new document dialog:

http://spandothers.wordpress.com/2013/04/24/sharepoint-replacing-the-new-document-button-with-something-functional/
http://www.macaw.nl/weblog/2012/8/extreme-new-document-button-makeover

All of these solutions create a popup window in which the proper template is selected. We opted for a different option, because pop-ups are generally UX unfriendly. We created a panel that would become visible when clicking the new button. That panel would be created based on a tree structure defined in the termstore. You store the document templates in a shared location, and also define that location in the termstore when creating the tree, by using local properties on the terms.

In the end it all comes down to one of two javascript calls to actually create the new document based on the appropriate template: createNewDocumentWithRedirect and createNewDocumentWithProgId. Both these solutions work, and while it can be tricky to get the attributes in the proper format, once that is done you should be solid… Until your client uses IE11. When using IE11, rather than creating a new document, the user is confronted with a SharePoint unexpected error “The template must exist in the Forms directory of this document library.”. The same javascript code works fine in IE10 though, or when you render the page in any other mode then IE11. So the template can’t be in an invalid location right? Right.

The difference between IE11 (or Chrome for that matter) and all other modes comes down to how the javascript is handled. Below you’ll find the actual javascript (from core.js) that is being called.

It turns out that the function ‘IsClientAppInstalled’ (called in createNewDocumentWithRedirect, displayed from line 56) returns false for IE11 and true for any other version of IE. This means that the next function called is createNewInBrowser rather than createNewInClient, even though we are positive the client has Office installed. That function is meant for InfoPath based forms, and not for documents, which causes it to crash.

To overcome this issue the solution is easy. We simply called createNewInClient directly, because we are certain all users do indeed have Office installed. Gotcha!

P.S., if there is anyone out there that is interested in the Termstore based New Document solution, let me know and I’ll draft up a different post containing the entire solution.

MCMS2002 migration to a SharePoint 2013 Metadata driven environment

As any SharePoint enthusiast will acknowledge, migrating an existing website to a SharePoint environment is no easy task. This task becomes increasingly difficult when the website is a non-SharePoint website containing 100,000+ pages and documents. Tagging and organizing content in such a way that users will still be able to find it, either through search or through site navigation, can be very difficult – especially when the source content is unstructured. And finally – how can you ensure that all existing URLs are properly converted to their new ones while maintaining the search ranking in the major search providers?

In this blog post I’ll show you, as well as provide you with examples on, how we managed to overcome these challenges.

Case explanation

Our customer had a website based on Microsoft Content Management System 2002 SP1, which had been in place for over ten years. In those ten years, the website had been modified to meet all customer requirements. It worked like a charm. But, because MCMS and SQL 2000 are no longer supported by Microsoft, the customer had to move to a new platform. Since publishing content through their website is one of the customers core businesses, they needed a robust platform that had extensive publishing capabilities. They chose SharePoint 2013.

Along with the platform change, the new website also has a very different way of presenting content to the visitor. Instead of browsing articles though a hierarchic structure, we went for a search driven site through the use of metadata. This meant that the use of metadata would be of vital importance. Because without it, how could you find an article?

This presented us with a major challenge. More than ten years of publishing content meant that over 70,000 pages and 30,000 documents had to be migrated to SharePoint 2013 and had to be provided with additional metadata. Our goal was after all to make the content meaningful, relevant and, most of all, easily searchable.

Underneath you will read in detail how we approached this challenge.

Exporting the existing content

The first step towards migrating the website was to export the existing content. Because we had to deal with different sorts of content (website pages, documents and images), we decided on a generic approach that would work for all file types. In order to meet this challenge, we created a custom tool that exported all content into an XML based file, so there would be one XML file per URL. This XML file contained all the information we needed to be able to create new content into our SharePoint 2013 environment. All webpages and documents were ordered in a logical folder based structure, so we could import based on the year of publication. Webpages published on May 2006 would be converted into an XML file with a folder structure like this: {export location}\{language}\20065\{articlename}.xml . Although the same principle was applied to documents and images, they were located in an extra subfolder named Documents or Images.

The XML files created were the only source of input we had for creating the new pages and their properties. That is why we had to make sure that these files contained as much information as possible. Along with the basic properties, such as publication date and title, we also added a keywords property, which was filled with the most important keywords on the page. As well as the keywords, the theme property was also of great importance for the new website. This theme property could be derived from the URL of the existing content. A small snippet of the final XML is displayed below:

Executing the export tool using the settings and configuration described earlier, resulted in a total of ~105,000 XML files. These files could then be used by the content creation tool for creating new content in our SharePoint 2013 environment.

Creating new content in SharePoint

The next step in the process was to create new content in our SharePoint 2013 environment using the exported XML files. For this process we created custom tooling that used a dynamic approach, with which our customer has the ability to easily control the output generated by the content creation tool. In order to be able to achieve this dynamic behavior, we combined two XML files that form the heart of the content creation tool.

The first XML file describes a mapping that, based on the URL property of the export, determines which contenttype is used for creating the new content, as well as which tag is added for search optimization. Below is a snippet of this XML file:

The second XML file describes which property in the exported XML file is mapped to which SharePoint Field. Below is a snippet of this XML file:

The flow of the content creation tool, which is executed for every input XML file, is displayed below:

Image

First, the contenttype is chosen based on the mapping file shown in Listing 2. Each contenttype has its own collection of fields that need to be supplied with information. For each field in this collection, we retrieved the appropriate value, based on the mapping shown in the earlier code snippit. To read the data from the XML mapping files, we created a generic method which is displayed in the code sample below. After all field values were retrieved, a new page was created based on the mapped contenttype, and the field values were set to their appropriate values. After that, the page is saved and published. Finally, an item was added to the URLRedirectList. This list can then be used to perform user redirection as described in the next paragraph.

Search provider friendly URL redirection

Migrating the website into SharePoint 2013 meant that all existing URL’s were invalid, since SharePoint stores pages and documents in a completely different directory. This would be easy enough to change in the import tooling for all internal links, however in this case we also had to consider the hundreds of thousands of external links to the website that have been created by various sites over the internet. We also had to make sure that all of these links would still be valid! And we wanted to perform the redirection to the new pages in such a way that search providers would maintain the page rating.

To tackle this problem, we developed a simple, yet very powerful, solution. We created a SharePoint list, containing two columns namely the old and new URL. As discussed earlier, each time a new page or document was created during the execution of the content creation tool, a new list item was added to this list. After the content creation was completed, we had a full list of URL’s to which we want our users to be redirected to when they visit an old URL.

In order to make sure that we could intercept a request before the user is returned a 404 error code, we had to create a custom HttpModule. The downside to this was that HttpModules execute on every request, even if the resulting page would not be a 404 error. To make the HttpModule as lightweight as possible, we first checked whether or not the request would end in a 404 status. Because we knew that all existing URL’s end in the .htm extension, this was our second check. Only if both comparisons are true, we would query the URLRedirect list to see if the user had requested an old URL.

The end result of the HttpModule is shown below. Please note that URLRedirectBE is a business entity class used for working with the URLRedirect list items in a strong typed manner. It retrieves a SharePoint listitem based on the oldURL column and maps the field values to public properties.

By using a redirection with a 301 status, we not only made sure that any existing ranking with search providers remained in place, but also when the user visits this URL through the same search provider again, they will no longer use the HttpModule.

In order to register the new HttpModule in SharePoint we created a web application scoped Feature with a feature event receiver which is displayed below.

The result is a user friendly redirection mechanism that takes the existing pages search provider ranking into account.

Conclusion

Migrating a website into a SharePoint 2013 environment is never an easy task. In this article we have discussed our dynamic approach using custom tooling and configuration XML files. The key point for every migration is to focus on what is important for the customer, and make sure that is translated to the best possible migration approach. For us, the generation of metadata throughout the content generation process was of vital importance. This ultimately allowed us to create a new website that had conceptually completely changed the visitors perspective, from a website based on a hierarchal structure to a search driven website through the use of metadata.


DIWUG logoThis post is also published as an article in #13 of the DIWUG magazine. Be sure to visit the DIWUG site for more interesting articles.

I did not do all the work myself, so I would like to thank the entire team. Be sure to check out the blogs from some of my team members as well:
Garima Agrawal – http://mysharepointlearnings.wordpress.com/
Sachin Sade – http://sachinvzade.blogspot.in/

SharePoint 2013 Quick Edit Bug when editing more than 30 documents

SharePoint 2013 introduces a new ‘Quick Edit’ function to replace the use of Datasheet views that was present in SharePoint 2010. Crystal posted two excellent blogs containing things to know about SharePoint 2013 Quick Edit, which you can find here:

http://www.boostsolutions.com/blog/things-to-know-about-sharepoint-2013-quick-edit-part-1/
http://www.boostsolutions.com/blog/things-know-sharepoint-2013-quick-edit-part-2/

A customer of ours uses this functionality for bulk editing new metadata columns when migrating content from their previous Intranet. One document library would contain several hundred items, which meant they exceeded the page item limit and would get multiple pages to browse through. As soon as they clicked to continue on to the second page, the quick edit mode would break. The quick edit was still enabled, but when clicking on any cell it would be greyed out, rather than have the blue highlight around it. This can be seen in the image below:

Image

Finding out what caused this strange bug took quite some time, so that’s why I’m sharing it with the world. We went through the different contenttypes and their fields to figure out if one of those was the source of the issue. That wasn’t the case. Then we checked if versioning had anything to do with it. Again – not the issue. In the end it turned out to be the presence of the default SharePoint Field ‘Edit (linked to edit item)’ in the view. As soon as we removed this field from the view, bulk editing meta data through several pages was no longer an issue:

Image

So in summary, if you experience issues where the quick edit fields are greyed out when browsing through a multi-paged document library, be sure that the field ‘Edit (linked to edit item)’ is not present in the current view. Gotcha!

PostSetupConfigurationTaskException was thrown when installing SP1

Last week we had to update our customer’s SharePoint 2013 environment to SP1. We first updated the development environement and the test environment and didn’t have any issues there. However, when updating the QA environment (multi-server), we ran into a strange error. The installation went fine, but the Product and Patch Configuration Wizard would continuously fail at step 9 ‘Upgrading SharePoint products’.
Naturally, we tried to get some detailed exception information from the logfile. However, the message below wasn’t exactly crystal clear:

SyncUpgradeTimerJob: sleeping for 10 seconds
04/15/2014 09:29:54 12 INF SyncUpgradeTimerJob: sleeping for 10 seconds
04/15/2014 09:30:04 12 INF SyncUpgradeTimerJob: Upgrade timer job failed. Return -1.
04/15/2014 09:30:04 12 ERR The exclusive inplace upgrader timer job failed.
04/15/2014 09:30:04 12 INF Entering function StringResourceManager.GetResourceString
04/15/2014 09:30:04 12 INF Resource id to be retrieved is UpgradeTaskFailConfigSyncDisplayLabel for language English (United States)
04/15/2014 09:30:04 12 INF Resource retrieved id UpgradeTaskFailConfigSyncDisplayLabel is Failed to upgrade SharePoint Products.
04/15/2014 09:30:04 12 INF Leaving function StringResourceManager.GetResourceString
04/15/2014 09:30:04 12 INF Entering function Common.BuildExceptionMessage
04/15/2014 09:30:04 12 INF Entering function StringResourceManager.GetResourceString
04/15/2014 09:30:04 12 INF Resource id to be retrieved is ExceptionInfo for language English (United States)
04/15/2014 09:30:04 12 INF Resource retrieved id ExceptionInfo is An exception of type {0} was thrown. Additional exception information: {1}
04/15/2014 09:30:04 12 INF Leaving function StringResourceManager.GetResourceString
04/15/2014 09:30:04 12 INF Leaving function Common.BuildExceptionMessage
04/15/2014 09:30:04 12 ERR Task upgrade has failed with a PostSetupConfigurationTaskException An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
04/15/2014 09:30:04 12 INF Entering function Common.BuildExceptionInformation
04/15/2014 09:30:04 12 INF Entering function Common.BuildExceptionMessage
04/15/2014 09:30:04 12 INF Entering function StringResourceManager.GetResourceString
04/15/2014 09:30:04 12 INF Resource id to be retrieved is ExceptionInfo for language English (United States)
04/15/2014 09:30:04 12 INF Resource retrieved id ExceptionInfo is An exception of type {0} was thrown. Additional exception information: {1}
04/15/2014 09:30:04 12 INF Leaving function StringResourceManager.GetResourceString
04/15/2014 09:30:04 12 INF Leaving function Common.BuildExceptionMessage
04/15/2014 09:30:04 12 INF Leaving function Common.BuildExceptionInformation
04/15/2014 09:30:04 12 ERR An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException: Exception of type ‘Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException’ was thrown.
at Microsoft.SharePoint.PostSetupConfiguration.UpgradeTask.Run()
at Microsoft.SharePoint.PostSetupConfiguration.TaskThread.ExecuteTask()

After a few hours of making sure everything was set up correctly, we finally found out the cause for this strange issue. It turns out that SharePoint doesn’t want anyone other than SharePoint managed accounts to have dbowner permissions for the SharePoint databases. In our QA environment however, access to the SQL Server is heavily secured, and corporate policies enforce certain domain groups to automatically get dbowner permissions. After we removed these permissions and ran the configuration wizard again, it finally completed without any issues. Sometimes, SharePoint puzzles me…