Create a Simple SharePoint 2013 Employee Directory on Office365 – Part 1 – Introduction

Employee Directories are a common feature of most Intranets. In fact, I’m working on Employee Directories for two different clients right now.

Bonzai Intranet Employee Directory Example

Bonzai Intranet Employee Directory Example

This is such a common need, that it’s firmly embedded in the fantastic work that my friends over at Dynamic Owl have built into their Bonzai Intranet product. We aren’t going to be able to do something as fancy as there is in Bonzai. But with a little work – not much coding at all – we can build a perfectly good Employee Directory for a small- to mid-sized organization.

There’s a great article by Ari Bakker (@aribakker) out there that shows how to set up a simple a Employee Directory on SharePoint 2013: How to: Create a Simple SharePoint 2013 People Directory. For this series, I owe credit to Ari for getting me started and showing me the main path. I encourage you to read Ari’s post as well.

On Office365, there are some nuances, however, plus I wanted to add some secret sauce to what I implemented. The example I’ll run through in this series is similar to the Bonzai approach, but uses mostly out of the box capabilities. The one “coding” piece is the custom Display Templates I’m using to show the alphabetic search across the top of the search results and the specific columns we want in the table listing.

Here were some of my requirements:

  • Show all current employees by default, with paging set at 50 (the maximum available with search results)
  • Display a simple to use filter based on the first letter of the last name, indicating which last name letter is currently active
  • Only “light up” letters of the alphabet when at least one person has a last name starting with that letter (no links that lead to no results)
  • Show appropriate refiners in the Refinement Panel
  • Display the search results in a more tabular way to imitate the [often Excel-based] phone listing which is common in smaller organizations
  • Offer some other sorting capabilities within the current view

My hope is that by following the steps in these posts, you’ll be able to build a simple but useful Employee Directory for your organization or clients. In the specific case I’m working on now, the organization has about 100 active employees. Based on your organization’s size and specific make up, you will probably want to tweak things along the way.

Here’s a view showing roughly where we’ll end up:

Employee Directory

If there are specific requirements you have that I don’t mention here, please add them into the comments and I’ll try to cover them.

Create a Simple SharePoint 2013 Employee Directory on Office365 – Part 2 – Set up an Employee Directory Page

The first step is, of course, to create a page where the Employee Directory will live. The approach we’re taking here is to use a page in the Search Site Collection in Office365. By default – at least in the tenants I’ve worked with – the Search Site Collection lives at https://[tenant name].sharepoint.com/search. This isn’t a sneaky hidden Site Collection like the ContentTypeHub (See: Hidden Content Type Hub on Office365 Tenants), but one that lives right out in the open.

When you go to the Search Site Collection directly, you’ll land on a very bland search page:

Search home page

You may also have created your own Enterprise Search Center, which may look a little different. It doesn’t really matter, though. All we want to do is to create a new page in the Search Site Collection you are using to house the Employee Directory.

Click on the cog (See the cog on the left as of this writing. It’s not unlikely that it’s taken on a new shape or color since then.The Cog) and then Site Contents. This should show you all of the Apps lists and libraries available in the Site Collection root. If you can’t get this far, then you may not have the appropriate permissions. Go directly to Jail, do not pass Go, and do not collect $200. You’ll need to talk to your Tenant or Site Collection Administrator to get the right permissions.

If permissions aren’t a problem, then click on the Pages App Library icon.

Pages Library

Once in the Pages library, go to the ribbon and create a new page.

Add a new page

When you select Page, you’ll end up on the page where you can create the page. What you’re looking for here is the “(Welcome Page) Search People” page layout. In the image below, the page layout is not available. If it is, choose it and keep rolling. If not, first take this little detour.

Choose Page LayoutClick on the cog, go into Site Settings, and choose “Page layouts and site templates” under the “Look and Feel” section at the top of the right column. (For some reason, even when I know where something is on this page, I have a tough time spotting the right link: everything looks the same. My trick is to use Ctrl-F in the browser to search for the right word rather than just scanning for it.)

Page layouts and site templates

In the Page Layouts section, add the “(Welcome Page) Search People” page layout.

 

Enable a page layout

The section should then look like this:

Enable a page layoutNow go back to the Pages library and create a new page. I’m calling mine “Employee Directory” with the URL set to Employee-Directory.aspx. Be sure to choose the “(Welcome Page) Search People” page layout.

Create Employee Directory page

When you click Create, you’ll end up back in the Pages library. Click on the Employee Directory page. It’ll look something like this, though if you see my photo it’ll be a little weird.

Employee Directory - CreatedBelieve it or not, you now have a fully functional page that will do much of what you want. For instance, if you type “Lastname:A*” in the search box, you’ll get all of the people whose last name starts with the letter A.

Lastname:A*But we don’t want to land on the page with nothing showing. That would require more work than we want people to do. Instead, let’s set the Search Results Web Part up so that it shows some of the people in the tenant by default.

Click on the cog and Edit Page. If you’ve never done this on a Search Results page before, you may be surprised to realized that it’s just a Web Part Page with some special Web Parts already set up for you. You’ll see that you have two Web Part Zones.

  • On the left, you have the Navigation zone. It contains only one Web Part: the Refinement Web Part
  • On the right, you have the Main Zone. It contains two Web Parts: the People Search Box Web Part and the People Search Core Results Web Part.

Employee Directory in edit mode
Click on the dropdown at the top right of the People Search Core Results Web Part and choose Edit Web Part. This will open the Tool Pane for the Web Part.

People Search Core Results Web Part Tool PaneThere’s a great deal we can do with these settings, but for now we are going to just do one simple thing. Click on the Change Query button. In the Query text box, simply add contentclass=spspeople. This sets the default search to return all people, filtered by whatever is in the search box. If you click the Test query button, you should see at least a few people show up on the right in the Search Result Preview box.

Checnge query to search for peopleClick OK to save the query, OK to save the Web Part settings, and Save on the ribbon to save the page. Now you should have a very rough first pass at an Employee Directory. You should see up to 10 people in the results, perhaps along with a photo (if they have one in their profile) and a little information about each person (if certain profile properties are populated). You my also see some strange “people-like” entities. These will usually be some crawler accounts, etc. We’ll take care of those later.

OOB People Search ResultsWhew. That’s probably enough for now. If you want to, try adjusting some of the settings in the Tool Pane for the People Search Core Results Web Part, but don’t go too crazy. In the next post in this series, we’ll look at how we can make some changes to the Display Templates so that our results are more helpful and robust.

Note: Mikael Svenson (@mikaelsvenson), my search guru and Jedi master, pointed out to me that adding contentclass=spspeople isn’t actually necessary. Once we have some other criteria in the search query, we won’t need it there. However, at this point since we don’t, and we’d like to see some people in the results, it serves a purpose.

Create a Simple SharePoint 2013 Employee Directory on Office365 – Part 3 – Create Display Templates

In the prior two parts of the series, I covered the idea of an employee directory (or associate directory, or person directory, or whatever you call the people in your company/organization/commune) and how to create the basic page. Once again, I want to give credit to Ari Bakker’s (@aribakker) post that shows how to set up a simple a Employee Directory on SharePoint 2013: How to: Create a Simple SharePoint 2013 People Directory.

I’m going to start with Ari’s Display Templates, but take them a bit further. What you’ll want to do here will vary based on the characteristics of your organization. What’s useful for an organization with 10 people will be quite different than what’s useful for one with 100k+ people.

The client I needed this directory for has about 100 employees. As with many organizations, the Employee Directory is effectively replacing something that has been maintained in Excel and emailed out regularly. Everyone prints it out and hangs up a copy in their cube. So we really want this directory to look a lot like that old-fashioned phone list. It will have a little more info and if the data maintenance side of things holds up, the data will always be current. At the same time, since we are using Display Templates, we’re well-positioned to expand the information we display over time.

In small- to medium-sized organizations like this, it’s helpful to have an alphabetic filter. I’ve been building similar things in SharePoint for a long time. (See: Alpha Selection of List Items in a Data View Web Part (DVWP)) They are great to add to plain old list views, too. I’ve created a Control Display Template which shows the alphabetical filtering links and an Item Display Template that shows each person’s details.

Here’s what the alphabetic filtering looks like:

Alphabetic Filtering

Note that several of the letters are not “lit up”. That’s because no one in the organization has a last name starting with I, Q, X, or Y. Few things are more annoying than clicking on a link like this only to be told that “Nothing here matches your search”.

Nothing here matches your search

If nothing matches, then why did you show me the link?!?!?! So there’s a little magic in the Control Display Template to figure out which letters should not be lit up. That logic will ensure that we only can click on letters where there are actual results, even as people come and go.

Like I said, there are two Display Templates here. These little buggers tend to work in pairs.

Display Template Layout

Source: http://msdn.microsoft.com/en-us/library/office/jj945138(v=office.15).aspx

Think of the Control template as the outer one and the Item template as the inner one which we iterate for every individual item in the result set coming back from search. This can be a little tricky and also a little confusing. Where should we draw that dotted line? Well, you’ll see a lot of inconsistency on this. In my two Display Templates for the Employee Directory, I’m using the Control template to display the alphabetic filter links and to create the table which will contain the items, but I’m rendering the table header in the Item template. That just seems to make more sense to me because that way the column headers sit with the rendering of the actual data, not is a separate place (the Control template). Another thing to consider here is that ideally we want the two types of Display Templates to work atomically: we should be able to mix and match different Control and Item templates based on our needs. For instance, in a really large organization, we may not need to check for which letter to light up, so we could just use a Control Template that doesn’t do that piece.

OK, enough chit-chat. Let’s look at the code.

I’ve created a folder in the Site Collection under _catalogs/masterpage to hold everything I’m doing here.

Employee Directory Code

In the real installation, that folder is named for the client, but here I’ve called it “_EmployeeDirectory”. Note the leading underscore: that ensures that the folder will always show up at the top of the listing under masterpage; otherwise I have to scroll a lot.

As you can see, I’m pretty organized about how I store things in the folder. I have subfolders for:

  • css – Any CSS files that are a part of this solution.
  • Display Templates – This folder structure mimics the one that SharePoint uses out of the box. I even mirror the subfolder names, like Search, so that it’s clear what type of Display Templates are in there. Because each of the Display Templates has a Content Type in it, SharePoint knows how to find the files in these custom folders.

Control Display Template If I had any custom JavaScript in the solution, I’d have a js folder, images files would go into an images folder, etc.

Here are the custom parts of the Control Display Template. The basic logic is this:

  • Line 3 – Include some custom CSS. In a full installation this would probably occur in the master page, but I’ve chucked it out to share the important bits here.
  • Line 4 – Include jQuery. I’m using jQuery to handle a bunch of things since it makes life easier.
  • Line 7 – This div is just the outer container for the template.
  • Lines 10-15 – Declare some variables we’ll need later
  • Lines 19-36 – Emits the markup for the alphabetic filters.
  • Lines 22-28 – Loop through all of the letters in the alphabet and make the calls to search to find out if that letter should be “lit up”.
  • Line 31 – Emit the hard-wired “All” link.
  • Lines 38-53 – This block is where I figure out which letters to unlight change the CSS for each. Yes, After fiddling around with this for a while, I decided to load the page with *all* the letter lit up, and turn off the ones that don’t have data behind them. This makes for a good regression if we have one: all the links will be lit up even if the script fails.
  • Lines 55-76 – This function called getSearchResultsUsingREST makes a call to the Search Service using REST and passes back a promise. Each call requests just the first result (rowlimit=1) and only the WorkId property (selectproperties=’WorkId’). This makes the call extremely “light”. We don’t need to know how many people fall into the letters bucket; we just want to know if *any* do.
<body>
	<script>
		$includeCSS(this.url, "~sitecollection/_catalogs/masterpage/_EmployeeDirectory/css/EmployeeDirectory.css");
		$includeLanguageScript(this.url, location.protocol + "//code.jquery.com/jquery-1.11.2.min.js");
	</script>

    <div id="Control_SearchResults">

<!--#_
		// Make REST calls to the Search API to "light up" the letters.
		var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		var letters = alphabet.split("");
		var lettersSearch = []; // Array to hold the AJAX promises
		var currentSearch = (location.href.indexOf("k=lastname%3A") > 0) ? location.href.split("k=lastname%3A")[1].substr(0, 1) : "";
		var thisPage = location.pathname;
_#-->                    

		<!-- Alpha selector container -->
		<div id="edir-alpha-links">
			<span><a href=_#=thisPage=#_>All</a></span>
<!--#_
		// Loop through the alphabet and make a call to the search API for each starting letter
		for(var i=0; i < letters.length; i++) {
			var searchTerm = letters[i];
			var letterClass = (currentSearch === searchTerm) ? "selected" : "";		

			// TODO Build the calls into one REST $batch. See: http://www.andrewconnell.com/blog/part-1-sharepoint-rest-api-batching-understanding-batching-requests
			lettersSearch[i] = getSearchResultsUsingREST("LastName%3A" + searchTerm + "*");
_#-->
			<span id="edir-alpha-links-_#= searchTerm =#_">
				<a class="_#=letterClass=#_" href="_#= location.pathname =#_#k=lastname%3A_#= searchTerm =#_*">_#= searchTerm =#_</a>
			</span>
<!--#_
		}
_#-->
		</div>
<!--#_
		// When all the requests have completed...
		$.when.apply($, lettersSearch).done(function() {

			for(var i=0; i < letters.length; i++) {

				var searchTerm = letters[i];
				var count = this[i];

				var letter = $("#edir-alpha-links-" + letters[i]);
				if(count == 0) {
					letter.html(searchTerm);
					letter.addClass("no-link");
				};
			}

		});

		function getSearchResultsUsingREST(queryText) {

			var result = new $.Deferred();
			var resultCount = 0;

			// We only need to fetch the first result for each letter to know if we should light it up
			// The sourceId is the GUID for the 'Local People Results' Result Source
			var searchUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='" + queryText + "'&sourceId=%27b09a7990-05ea-4af9-81ef-edfab16c4e31%27&rowlimit=1&selectproperties='WorkId'";

			var p = $.ajax({
				url: searchUrl,
				method: "GET",
				headers: { "Accept": "application/json; odata=verbose" }
			});

			p.done(function(data) {
				// Return just the count of results, which will be 0 or 1
				result.resolveWith(data.d.query.PrimaryQueryResult.RelevantResults.RowCount);
			});

			return result.promise();
		}

_#-->

Next up is the Item Display Template. In this one, I’ve gone as simple as possible. Ive gotten rid of a lot of the encoding, null value tests, etc. that most of the out-of-the-box Displey Templates have just to keep it simple. Below I’m showing *everything* in the body of the template. It’s really stripped down.

 

  • Line 9-21 – If this is the first item in the result set, emit the table header.
  • Line 23-33 – Emit the details for each person in the rsult set. Here I’m showing:
    • Name (full name)
    • Work Phone
    • Email
    • Department
    • Office

Your organization will undoubtedly have a few other fields you want to add, you may one to remove one or two of these, etc.

<body>
    <div id="Item_Person">
<!--#_
		if(!$isNull(ctx.CurrentItem) && !$isNull(ctx.ClientControl)){
			var encodedPath = $urlHtmlEncode(ctx.CurrentItem.Path);
_#-->
<!--#_
			// If this is the first item in the results, emit the table header
			if(ctx.CurrentItemIdx === 0) {
_#-->
				<thead>
					<tr class="ms-viewheadertr ms-vhltr">
						<td class="ms-vh2">Name</td>
						<td class="ms-vh2">Work Phone</td>
						<td class="ms-vh2">Email</td>
						<td class="ms-vh2">Department</td>
						<td class="ms-vh2">Office</td>
					</tr>
				</thead>
<!--#_
			}
_#-->
			<tr>
				<td class="ms-vb2">
					<a clicktype="Result" id="NameFieldLink" href="_#= encodedPath =#_" title="_#= ctx.CurrentItem.PreferredName =#_">_#= ctx.CurrentItem.PreferredName =#_</a>
				</td>
				<td class="ms-vb2">_#=ctx.CurrentItem.WorkPhone=#_</td>
				<td class="ms-vb2">
					<a href="mailto:_#=ctx.CurrentItem.WorkEmail=#_">_#=ctx.CurrentItem.WorkEmail=#_</a>
				</td>
				<td class="ms-vb2">_#= ctx.CurrentItem.Department =#_</td>
				<td class="ms-vb2">_#= ctx.CurrentItem.OfficeNumber =#_</td>
			</tr>
<!--#_
	}
_#-->
    </div>
</body>

Finally, here’s the CSS I included above:

/* Alpha links for search */
#edir-alpha-links {
	margin-top:10px;
}
#edir-alpha-links span {
	padding:0 3px 0 3px;
	width:35px;
	font-size:18px;
}
#edir-alpha-links span.no-link {
	padding:0 6px 0 6px;
}
#edir-alpha-links span a {
	padding:0 3px 0 3px;
	border-radius:6px 6px 6px 6px;
	background-color:#005581;
	color:#fff;
}
#edir-alpha-links span a.selected {
	background-color:#E08B24;
}
/* Alpha links for search */

Please don’t use this as-is. I’m so disappointed when I see one of my examples shows up somewhere with exactly the same colors and fonts!

Once we’ve switched to these Display Templates, we have something like this:
Employee Directory - Part 3

You can see we still have a few oddities here. This screen grab is from my demo environment, so there aren’t that many real people in the results. (Note that only a few of the letters are lit.) We’re also seeing some odd “people” that aren’t people at all. There’s probably some other filtering we’d like to do, maybe a few more settings to tweak. Next up I’ll show you some of the things you’ll probably want to do with your Search Schema to make things work a little better. WARNING: Powershell is coming. Sad, but true.

Here are the files from this post in a ZIP file: _EmployeeDirectory Display Templates and CSS

Create a Simple SharePoint 2013 Employee Directory on Office365 – Part 4 – Search Schema

In the prior posts in the series, we’ve seen how to set up a page for our employee directory and then create Display Templates to render the information we want for each person, along with a nice alphabetical filtering capability.

Up to this point, things have worked pretty much the same as they would in an on premises installation of SharePoint. With Office365, though, this is where things get a lot more complicated. I want to thank my search guru Mikael Svenson (@mikaelsvenson) for his assistance with this part of the work. This is another instance with SharePoint where the steps should be simple, but they aren’t when you add Office365 into the mix: it only gets harder.

In the listing we’ve made so far, we’ve had little trouble displaying the User Properties we want to see in the directory. Adding in some slicing and dicing requires a bit more fancy footwork. After all, if we can’t find people, it’s not much of a search-based solution, is it?

Each property we want to use in a filter we build needs to be “Sortable”. If we want to use a property in a refiner – those lists of values on the left side of the Search Results page – those properties must be “Refinable”.

For some unfathomable reason, out of the box the LastName property is not “Sortable”, nor is it “Refinable”.  The FirstName is “sortable”, but to me it’s a lot less likely that you’d want to sort or filter on FirstName than LastName. If we want to sort by Lastname, we’re out of luck. In Ari Bakker’s (@aribakker) post that shows how to set up a simple a Employee Directory on SharePoint 2013: How to: Create a Simple SharePoint 2013 People Directory, he shows how to tweak the Lastname property to make it sortable.

If you go to the Search Schema settings (Admin / SharePoint / search / Manage Search Schema), you’ll see that this is the case.

2015-02-06_14-45-42


Update 2016-11-02: Thanks to eagle eyed reader David (see his comment below), the LastName Managed Property is sortable on Office 365 now, at least in one of the tenants I checked. If that’s the case in your tenant, you won’t need to jump through this set of hoops.


In Office365, we’re not able to change the attributes of the out of the box User Profile properties, though. If we try to, they are all simply grayed out; we can’t touch them. This is where our path diverges from on premises installs.

On Office365, there is a very big set of dummy properties named RefinableString00, RefinableString01, etc. There are 100 of these String properties. There are also sets for Date (20), Decimal (10), Double (10), and Int (50). If you need any more of any of these, you’re stuck, so use them wisely.

Search Schema - Refinable Strings

Because the Lastname is a a string-valued property, we’re going to use one of the RefinableString dummy properties. What we do is map the RefinableString property to a crawled property. Here I’ve chosen RefinableString00 because I haven’t used it yet. Here are the steps to set up the mapping:

  • Click on the RefinableString00 property in the search schema listing
  • Scroll down to the section for Mappings to crawled properties
  • Click on the Add a Mapping link
  • Find People:LastName by typing “Lastname” in the search box and clicking “Find”

2015-02-06_14-52-51

 

  • Select the People:LastName property and click OK
  • You can only map to one Crawled Property, even though the UI will allow you to select several. As much as I wanted to include People:SPS-PhoneticLastName to match the LastName Managed Property, I couldn’t. I had to settle for just People:LastName, (which should be fine).

Lastname Mapped Properties

  • Scroll to the Alias setting and give the property a name you’ll recognize. I’ve used LastnameSortable.

Add Alias

  • Save the RefineablerString00 property by clicking OK

Now you still have a property named RefinableString00, but it has an alias of LastnameSortable (if you used the same name as I did) and it is mapped to the People:LastName property, meaning that RefinableString00 will get the same values as People:LastName.

RefinableString00 Configured

Perfect, right? Now we can just use that LastnameSortable property in our slicing and dicing tools and we’ll be all set!

Not so fast, Kemosabi. On Office365, we have no control over search crawling. We can’t just fire off a crawl to update the index like we can on premises. (In either case, we have to be admins, but that’s not the difference here.)

A User Profile will only be re-indexed if a value in that profile changes. For example, if I change my MobilePhone or a new value syncs over from Active Directory, then the next crawl will pick up that change and the value will be available in the search index. We’ve mapped the People:LastName property to the RefinableString00 property, but since no User Profiles were changed in the process, it makes no difference. We can’t just push the re-index button on Office365.

The only way we (Mikael, and therefore I) know to change every User Profile so that it will be indexed is to run a Powershell script that “touches” every profile. This is down and dirty stuff, folks, and not for the squeamish. You might want to enlist your local Admin Superhero to help you with this part.

2015-02-06_14-58-03Mikael built a script that loops through all of the User Profiles; copies the SPS-Birthday property value; sets the SPS-Birthday property to an arbitrary value; saves the profile; sets the SPS-Birthday back to the original, saved value; and saves the User Profile. Yes, for every single User Profile in the User Profile Store.

The one problem I had was that SPS-Birthday was almost never available in the User Profiles in the organization I was working with. Mikael adapted his Powershell script to also work with Department, which ought to be there more often. For the company I originally muddled through this with and their 100 or so employees, this wasn’t a big deal; the Powershell script ran through in a few minutes. If you are in a larger organization, the script might take hours and could possible timeout along the way. That said, it will work. Eventually.

I’m not going to go into all of the details on how to run the Powershell script. Instead, head on over to Mikael’s post “How to trigger re-indexing of user profiles in SharePoint On-line” and follow his instructions.

Once you’ve run the script, you’ll need to wait for some period of time – we don’t have any way of knowing when these crawl jobs actually happen. Experience shows that this will be 2-8 hours, but it can depends on the load in your tenant’s hardware. Once the values are indexed, you can start to use them in your Employee Directory.

The next step is to add some of the slicing and dicing capabilities. We couldn’t do that before we set up the RefinableString00 aka LastnameSortable property. If we had tried to use the Lastname property, we’d just get errors in the page I know this from experience). Errors that tell us precious little about what the actual problem is. Correlation ID!

Ari’s post shows some slick additional sorting capabilities that it would be nice to add at the top of the page. Sorting by Lastname or Firstname might make finding the person in the middle of the list by default a little easier to find. In the next article in the series, I’ll show you how to set those sorting capabilities up.

Create a Simple SharePoint 2013 Employee Directory on Office365 – Part 5 – Sorting & Refiners

This post in the series was sitting in my “outbox” for a long time. Sorry to people like Nigel (@Nigel_Price) who probably gave up on me!

In a company with 100 employees, clicking on once of the letters are the top of the page will probably narrow things down well enough that you’ll see everyone with that letter at the start of their last name on one page. If you have many more employees, you may end up with too many people to see very easily. And since we’re limited to 50 results in the Search Results Web Part, you may need to page and/or scroll a lot, depending on what properties you’ve decided to show for each person (one line vs. two lines or more, for example).

There are a couple of out of the box capabilities we can use to sort or filter our results a bit more. Because we’re using search to drive the directory, we have all of the native search capabilities that SharePoint gives us. Let’s take a look at adding some sorting and improving the refiners.

Sorting

In the Web Part Properties for the Search Results Web Part, there is a checkbox labelled “Show sort dropdown”. It’s in the Settings section (which is full of other options as well).

2015-02-26_12-04-17

By checking the box and adding some of our own JSON into the field below it, we can control what sort options are available. The JSON should be an array of sort options taking this form:

{
    "name": "Last name (A-Z)",
    "sorts": [{
        "p": "RefinableString00",
        "d": 0
    }]
}

The values break down like this:

  • name – The text value you’ll see in the dropdown
  • sorts – The parameters for the sort that apply when the option is selected
    • p – The managed property to sort on
    • d – [0 | 1] If 0, the assort is ascending, if 1 it is descending.

Note that for the Last name sort above, I’m using the RefinableString00 managed property I set up in Part 4. If we tried to do this with the LastName managed property we’d get an error because that property is not Sortable.

Here’s a pretty basic set of sorting options that should at least get you started. I’m giving you four pretty basic sort options:

  • First name (A-Z)
  • First name (Z-A)
  • Last name (A-Z)
  • Last name (Z-A)
[{"name":"First name (A-Z)","sorts":[{"p":"FirstName","d":0}]},{"name":"First name (Z-A)","sorts":[{"p":"FirstName","d":1}]},{"name":"Last name (A-Z)","sorts":[{"p":"RefinableString00","d":0}]},{"name":"Last name (Z-A)","sorts":[{"p":"RefinableString00","d":1}]}]

You should be able to take this and enhance it for your own needs.

Refiners

Next we probably want to adjust the refiners a bit. Out of the box, the Refiners Web Part will display properties that look to a machine like useful ones, but they may not be the most useful in your organization. You may want to show refiners that are part of the search results already or you may want to show refiners that aren’t visible in the results.

Changing which refiners you see and in what order works like this:

  • Edit the page
  • Put the Refinement Web Part into Edit Mode
  • Click on Choose refiners
  • Change the settings
  • Save it

The key action here is to add or subtract from the Selected refiners in the Choose refiners dialog. For each refiner, you can change the settings on the bottom of the page. Note that refiners use Display Templates as well. I’m not going to go into building Refinement Display Templates, but you can see them in _catalog/_masterpage/Display Templates/Filters.

In my case, I’ve got refiners for Department, JobTitle, PeopleKeywords, and BaseOfficeLocation. You will probably want some others which work for you.

Refinement configuration

You should see the impact of these changes immediately upon saving the page. Assuming that the properties you have selected have been indexed, that is.

What Next?

There are a number of different directions we could go from here. We could build a similar page to show a Site Directory [Nigel]. We could enhance the display of each person to show additional information about them or metrics about their recent activities. We could add as second alphabetical listing row below the first so that if you selected the letter B, you could the choose the next letter (only lit up if there are people lurking there). As with most functionality like this, coming up with the innovative ideas can be even harder than good execution on them. In this case, some of the limitations in Office 365 make it even more difficult that it should be.

I’d love to see:

  • Ability to trigger a full crawl of the User Profiles when we change the schema. It wouldn’t have to happen right away, but it would at least remove the need for Powershell.
  • Allow us to build a more intelligible set of “RefinableType” properties so that we can manage them better. If we create more than a handful of these special mappings – as most organizations will do over time – then management is going to be cumbersome at best. We can’t even search by the Alias names.

Then basic process here should work for many different use cases. As you’ve probably gleaned from this series, building good metadata and taxonomy isn’t just an academic exercise. The whole point is to make content easier to find, and a People Directory is no different: it’s a customized page that allows us to perform a certain used case in an optimal way. What “optimal” means is going to vary based upon the characteristics of your organization.

  • How big is it?
  • Why would people be looking for each other (beyond the simple phone list idea)?
  • What information is important for people to see vs. that which must be secured?
  • etc.

I hope you’ve found the series useful. If you’d like to know more or have other ideas, I’d love to hear about them in the comments below.

References