Using Dynamically Created Angular Directives with SharePoint Display Templates

Paul Galvin
3 min readSep 12, 2016

--

I’m building a solution these days that includes the notion of a “favorite.” It’s pretty similar to a web browser favorite, but these are all self-contained in the universe of this little application and manipulated by the application here and there.

Following normal Angular patterns, I have a service that contains all the logic for managing favorites (standard CRUD operations). We wanted to incorporate the ability to add or remove an item from the user’s personal favorites via search. This screenshot shows the desired experience:

She Loves Me, She Loves Me Not

If something is already a favorite, it renders as a filled-in heart. If not, it shows as an open heart. Clicking on the heart toggles the status.

As I wrote above, there’s an angular service that manages the communication to SharePoint for us. A custom angular directive that the UI and connects a user’s mouse clicks to the controller. It’s one big happy Angular family.

The trick is — how to get this working with a search display template? In the end, it’s pretty easy, but took a bit of sleuthing.

Step One: Ensuring Angular is Good to Go

All the Anglar bits have to be present by the time SharePoint search renders your display template results. I do this using a content editor web part on the page with a bootstrap html file. This bootstrap file has a bunch of script tags, including Angular and your custom service (plus any other libraries that you need, etc.). There is not logic here and no JS runs other that the usual Angular IIFE’s.

Step Two: Bootstrap Angular From Within the Display Template

The display template itself is going to emit the markup for the directive that handles the heart toggling. This is the code:

Giving Angular the Boot

This is the first bit of code that executes when the display template warms up. The “boostrap_guard” ensures that it’s only bootstrapped once.

Since I’m emitting the directive after Angular bootstraps, I need to use the $compile service. The output of that has to be added into the DOM at the right place. To this end, I need a way to uniquely identify the eventual insertion point. I do that thusly:

Tracking IDs for future use

Step 3: Making Room for the Angular Directive

In this scenario, we just make a placeholder for the directive:

A place for everything and everything in its place

Step 4: And Now, the Good Stuff

It’s important to add the directive dynamically because this version of SharePoint (or at least the flavor with which I’m working — SPO and O365) uses async techniques when responding to user clicks such as refiners. This is how it works:

Render Me, Baby!

At line 99, it creates the actual HTML markup for the directive.

At line 104, it grabs a handle of the insertion point DOM element.

At line 108, it does the Angular magic:

  • Line 108 converts the jQuery element to an Angular element. It grabs the Angular injector and invokes the $compile function.
  • Line 109 gets the angular $scope.
  • At line 110, it appends the $compile’d element onto the insertion point from Step 3.
  • At line 111, it invokes $apply, notifying Angular that it has as new directive to manage.

It’s a Wrap!

At the end of the day, it’s pretty simple:

  1. Bootstrap Angular.
  2. Decorate some DOM element with an ID so that the compiled directive can be inserted.
  3. Compile and insert the compiled markup.

Piece of cake.

Happy coding!

</end>

--

--

Paul Galvin

Author and Practice Director @ Neudesic/IBM. Father, Not-Great-But-Always-Trying Zen Buddhist. “Yet Another TypeScript Book” (https://amzn.to/2ABntAX).