In this post I want to show you step-by-step implementation of SharePoint Framework Application Customizer.
UPDATE: on 9/25/2017 SPFx Extensions were GA-ed. The post is updated to contain the latest version of API.
UPDATE: on 8/29/2017 Release Candidate was announced. The post is updated to contain newer version of API.
Use Case for the sample:
Your team is working on some project and you're using SharePoint Tasks list to assign and monitor tasks in the project. You want to notify a member of your team that he or she has overdue tasks. You want this notification to be available on any page on your site and also to provide link to the Tasks list view filtered by current member and by due date.
The result may look like that:
Key features of the sample:
- SPFx Application Customizer implementation
PrerequsitesBefore following the steps in this article, be sure to proceed next 3 steps:
- Get Office Developer Tenant (you can get one for free by subscribing to Office 365 Developer Program. It's an optional step as Extensions reached General Availability but it's good to have the tenant to be able to get preview versions in future.
- Set up your development environment
- Create Tasks list on your tenant's site
- Insert custom HTML to well-known locations on the page - Placeholders
- onInit() – runs code before page DOM is ready. Perform needed setup here
- this.context.application._layoutChangedEvent – event that gets raised every time the layout changes in a page. It's marked as internal but still available for usage
- this.context.application.navigatedEvent – event that gets raised every time there is a page navigation
- this.context.placeholderProvider.changedEvent – event that gets raised when the list of currently available placeholders is changed
- this.properties – properties that are passed to the customizer
- this.context.pageContext – standard definitions for common SharePoint objects (site, web, user, list, etc.)
- this.context.httpClient, this.context.spHttpClient, this.context.graphHttpClient – helpers to send http requests, http requests with SharePoint context and Microsoft Office Graph requests
- this.context.placeholderProvider – helper object to work with placeholders.
- this.context.application – helper object to work with "application". For now it can be used to attach to application's events.
Working with Placeholders
- Currently available placeholders (as of Oct 2, 2017): Top, Bottom
- Import PlaceholderContent and PlaceholderName definition:
- Get placeholder instance:
- Insert markup:
Scaffolding the ProjectFirst step in any SPFx project is to "scaffold" it using Yeoman SharePoint Generator. "Scaffold" in more classic terms means generate or create from a template.
Here are the steps to create a project.
- Open Command Prompt (Terminal in MacOS) or any Console tool
- Create a new directory for the project in the location you want
- Go to the created directory
- Start scaffolding new project with Yeoman SharePoint Generator
- When prompted
- Accept default solution name (overdue-tasks)
- For baseline packages select SharePoint Online only (latest) as SPFx Extensions are not available for SharePoint 2016
- Select Use the current folder
- You can select either y or N for availability of your extension across tenant. It depends on how you're going to install it. If you use Feature Framework to add application customizer then this option will not work as it doesn't work with Feature Framework
- Select Extension as a client-side component
- Select Application Customizer as an extension type
- Type OverdueTasks as a name
- Accept default description
- Wait until Yeoman is installing all needed dependencies
Note: this is a TypeScript project so select the IDE that supports TypeScript language. I'm using Visual Studio Code.
The project structure should look like the one on the picture below
Debugging the Extension using gulp serve and query stringI decided to put this section at the beginning so you could run the code each time you want to check if everything works fine.
SharePoint Framework extensions cannot currently be tested using the local workbench, so you'll need to test and develop them directly against a live SharePoint Online site. You do not however need to deploy your customization to the app catalog to do this, which keeps the debugging experience simple and efficient. First, compile your code and host the compiled files from the local machine by running this command:
If the code compiled without errors the server will be running on http://localhost:4321.
To test the extension
- Go to SharePoint Dev tenant
- Open any list/document library/modern page
- Append next query string parameters to the list's URL:
- loadSPFX=true ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework is not normally loaded unless at least one extension is registered. Since no components are registered yet, we must explicitly load the framework.
- debugManifestsFile=<URL> specifies that we want to load SPFx components that are being locally served. Normally the loader only looks for components in the App Catalog (for your deployed solution) and the SharePoint manifest server (for the system libraries).
- customActions simulates Custom Action. The Key here specifies the GUID of the extension that should be loaded - ID value is located in manifest.json file of the extension. Location parameter should be ClientSideComponent.ApplicationCustomizer for this type of customizer. The properties parameter is an optional text string containing a JSON object that will be deserialized into this.properties for your extension (we will modify it later for the purposes of the sample).
- Accept loading of Debug Manifests
- You should see a popup
Adding Additional LibrariesNext step is to add external libraries (modules) that will be used in the project.
In this sample we'll need to request data from SharePoint (overdue tasks and also a URL to redirect user to the Tasks list).
It may be done with REST API using this.context.spHttpClient helper. But I prefer to use SP PnP JS library which provides great syntax for generating REST requests.
PnP JS library can be added using npm package manager:
- In Command Prompt (Terminal) go to project directory.
- Install the PnP package
Getting Data from SharePointAs mentioned earlier we need to get overdue tasks and Tasks list url from SharePoint. And to get that data we need to know Tasks list id or Guid. It can be hardcoded but it's better to use this.properties object for that. Let's modify IOverdueTasksApplicationCustomizerProperties interface which describes what members will be available in this.properties:
So, all the code inside onInit should be wrapped with the Promise constructor:
And when the response is received we're constructing the Url using Late Tasks view Url and filter by current user.
Why Late Tasks view? Because it has filter to show overdue tasks only.
Additionally you may notice usage of escape function when creating filter parameters in Url Query Strings. This function is imported from sp-lodash-subset module:
The request is also added to the batch.
The last command in onInit would be to execute batch. When the batch is executed we can finally call the method to render our content and resolve the promise:
First thing to do here is to check if there are overdue tasks as there is no need to display message if there are no overdue tasks:
First, let's import PlaceholderContent and PlaceholderName definitions from sp-application-base:
In this sample we don't have any additional resources so the handler has no code. But it can be used, for example, to dispose React component.
And the last step is do add a markup:
DeploymentDeployment of any SharePoint Framework solution is done similarly to the deployment on SharePoint Add-ins:
- Package the solution
- Deploy the solution to App Catalog
- Install the app to the specific site
The second one will create .sppkg file in solution_folder/sharepoint folder and also prepare all the assets to be deployed to some storage. It may be Office 365 CDN, Azure Storage or any other type of public or organization storage. Preparation of the storage is a large separate topic. You can read about Office 365 CDN here and about Azure CDN here.
After the solution is packaged and the assets are deployed to some CDN the solution can be deployed (manually or using some custom routine) to App Catalog and later installed to some site.
By default, the application customizer will be available as soon as the app is installed to the site. If you need some custom logic that will optionally activate the Customizer you can use CSOM/JSOM for that:
- Delete elements.xml in solution_folder/sharepoint/assets
- Remove feature from package-solution.json that references elements.xml
- Deploy the solution to App Catalog and install on the site
- Get Web CustomActions collection:
- Add new CustomAction with correct ClientSideComponentId and ClientSideComponentProperties: var ca = customActions.Add(); ca.ClientSideComponentId = new Guid("customzier_id"); ca.ClientSideComponentProperties = "customizer_props"; ca.Title = "Application Customizer Title"; ca.Location = "ClientSideExtension.ApplicationCustomizer"; ca.Update(); web.Update(); ctx.ExecuteQuery();
And that's it!
Now you should be ready to create your Application Customizers, debug them and deploy. You can get the code from GitHub repo