How To Pass Parameters To SPFx Extension By Creating A WebPart UI Interface

I hope you have a basic understanding of SPFx extension application customizers. If not, I would suggest you go through this link to understand the basics on SPFx extension.

The "Hello world" example provided by Microsoft on application customizer by using a placeholder shows that we have to hard code the HTML in the code itself which we want to show on pages. While I was trying this example, the below thoughts came to my mind.

  • We are hard-coding HTML in the code itself. If there is a slight change, you might have to upload a new version of the app.
  • How can I disable the automatic activation of Extension features which adds customization on app installation?
  • How can I pass dynamic parameters to SPFx extension based on user input?
  • How can I provide a user interface to add/modify/delete header and footer based on the user's preference without changing the code and going through the redeployment process?

We want to add a custom header or a footer to SharePoint modern page but want to give admin an interface to provide HTML of his choice and then pass it to SPFx extension application customizer to add it on the top or bottom.

My idea here was to provide a configuration option to site admin/users to provide their custom HTML. To do this, we would have to combine the web part and extension in a single package. I have created a running solution and uploaded to GitHub for others to use. This can be a reusable component which can be used in multiple site collections having their own header and footer, just by configuring with the web part. The below code snippets are part of the same solution.

A few points to understand:

  • Application customizer is added to the site using custom action.
  • An association is created between custom action and application customizer.
  • To enable application customizer manually, we need to create a user custom action.
  • The below 3 properties of custom action will associate it to application customizer.

    • Location - Its value should be 'ClientSideExtension.ApplicationCustomizer', based on on extension type.
    • ClientSideComponentId - this should be the Id of your application customizer, this id you can get from applicationcustomizer.manifest.json. Copy the id attribute value.
    • ClientSideComponentProperties - this is where you can pass your custom properties value in JSON as a string.
  • Once you add a custom action via REST API with the above attributes it will create a custom action and also enable your extension.

As per this example what we will do is create a web part inside the same solution (having extension). Within a web part, add a simple input text area and button. On click of button setCustomAction method is called.

Below is the code snippet for quick reference. (all this code should be in your webpart.ts),
  1. protected setCustomAction() {  
  2.  try {  
  3.    var title = 'SettingHeaderFooterwithAppCustomizer';  
  4.    var description = 'This user action is of type  application customizer to add header footer or custom javascript via SFPx extension';
  5.    var headtext =  document.getElementById("headerText")["value"] ;  
  6.      this._getdigest()  
  7.        .then((digrestJson) => {  
  8.          console.log(digrestJson);  
  9.   
  10.          const digest = digrestJson.FormDigestValue;  
  11.   
  12.          const payload = JSON.stringify({  
  13.              
  14.              Location: 'ClientSideExtension.ApplicationCustomizer',  
  15.              Title: title,  
  16.              Description: description,  
  17.              ClientSideComponentId: 'fc14316e-72db-4860-8283-458154eaef3e',  
  18.              ClientSideComponentProperties: JSON.stringify({myprop:headtext }),  
  19.          });  
  20.          const headers = {  
  21.              'X-RequestDigest': digest,  
  22.              "content-type""application/json;odata=verbose",  
  23.          };  
  24.          const spOpts: ISPHttpClientOptions = {  
  25.            body:payload  
  26.          };  
  27.          this.context.spHttpClient.post(this.context.pageContext.web.absoluteUrl + `/_api/site/UserCustomActions`, SPHttpClient.configurations.v1,spOpts)  
  28.            .then((response: SPHttpClientResponse) => {  
  29.               console.log( response.json());  
  30.             });  
  31.            });  
  32.  } catch (error) {  
  33.      console.error(error);  
  34.  }  
  35. }  
Get Digest method to get digest value for POST method.
  1. private _getdigest(): Promise<any> {  
  2.   
  3.  const spOpts: ISPHttpClientOptions = {  
  4.  };  
  5.  return this.context.spHttpClient.post(this.context.pageContext.web.absoluteUrl + `/_api/contextinfo`, SPHttpClient.configurations.v1,spOpts)  
  6.    .then((response: SPHttpClientResponse) => {  
  7.      return response.json();  
  8.    });  
  9. }  
Render method to show how to add textarea and button,
  1. public render(): void {  
  2.      this.domElement.innerHTML += '<textarea id ="headerText" rows = "5" cols = "50" name = "description">Enter Header HTML</textarea>'
  3.      this.domElement.innerHTML += '<button type="button" id="btnRegister">Click Me!</button>';  
  4.      this._setButtonEventHandlers();  
  5.  }  
Method to bind click event of button (yes this is how we have to do it):
  1. private _setButtonEventHandlers(): void {  
  2.   const webPart: WpConfigureApplicationCustomizerWebPart = this;  
  3.   this.domElement.querySelector('#btnRegister').addEventListener('click', () => {  
  4.     this.setCustomAction();  
  5.   });  
Note
Make sure you remove custom actions before adding a new one because SharePoint will create custom actions on every button click and it would start adding n number of HTML instances of header/footer.
 
I hope this helps. Happy Coding!