05 February 2024

Build a Form Customizer Extension using SPFx and apply it to any SharePoint Online List

Introduction

When you have a SharePoint Online list, you can normally create new items, edit items or just simply open and read an item. Each time you do this, you will experience the out-of-the-box form that is rendered by SharePoint. But what if you want to customise the form experience itself, so that it renders it how you want it to look when you create a new item, edit an item or open it for reading? You can develop a Form Customizer Extension using SPFx, which is what this post will outline.

There is a very useful Microsoft learning article on how to create a simple form customizer extension, and this is found here: Build your first Form Customizer extension. The steps contained within this Microsoft article involves creating a simple custom list called 'Business' which has only got the one default 'Title' column. The remaining steps in the article then created a simple form customiser extension that custom rendered that one input field (mapped to the Title column), together with a save and cancel buttons from scratch. However, in the most likely scenario, that you have a more complicated custom list that you want to target, there is obviously a bit of work involved to custom render all of the fields and controls. In the same article, the extension also was created using the 'No framework' option.

So instead of choosing 'No framework', what this post will do, is use the React Framework and the PnP SPFx DynamicForm control. The benefit of using the PnP SPFx DynamicForm control is that you do not have to add lots of code to custom render all the fields yourself, the control does it for you once you choose your target list!

Installing Pre-requisites

To follow this approach using SPFx, you will need to setup your SharePoint Framework development environment. This can be found here: 
Set up your SharePoint Framework development environment. This will involve installing Node, Visual Studio Code (VSCode), Gulp, Yeoman and the Yeoman SharePoint Generator.

As mentioned earlier, there is a Microsoft learning article on how to create a simple form customizer extension, and this is found here: Build your first Form Customizer extension. The ability to create a form customizer was released as part of SharePoint Framework v1.15. So you will need at least this version. I currently use v1.18.2.

Once you have Visual Studio Code installed, you can use the Terminal to type in:

 npm list -g --depth=0 
  
                    
This will show a list of what's installed and their versions. I had the following:

C:\Program Files\nodejs -> .\
├── @microsoft/generator-sharepoint@1.18.2
├── corepack@0.19.0
├── gulp-cli@2.3.0
├── npm@9.8.1
└── yo@5.0.0
 
Then, to determine what version of node you are using type:

 node --version 

For me this returned:  v18.18.2

Now we are ready to start!

Creating our extension project

Create a new project folder (directory) in a destination of your choice. In VSCode type this in your terminal:

 md form-customizer 

Then go to your project folder:

 cd form-customizer 

Once you are there, we run the Yeoman SharePoint Generator command:

 yo @microsoft/sharepoint 

You will be presented with the following prompts, so answer them as follows:

What is your solution name? form-customizer
Which type of client-side component to create? Extension
Which type of client-side extension to create? Form Customizer
What is your Form Customizer name? Demo
Which template would you like to use? React

After this, the required dependencies will be installed to scaffold the solution and create the extension.

Opening the solution in VSCode

If the explorer is not visible in VSCode, open it now by doing:
File > Open Folder... > then select the form-customizer folder.

Or you can do:  code .   and it will open another instance of VSCode with the solution folder already open.

Install the PnP SPFx Controls for React

We now have to install the PnP SPFx controls in order to use the DynamicForm control. In VSCode, within your terminal type in the following to install the PnP SPFx React controls for your SharePoint solution:

npm install @pnp/spfx-controls-react --save --save-exact

This will install a whole range of reusable React controls. More information on those can be found here: https://pnp.github.io/sp-dev-fx-controls-react/.

We will be using specifically just the DynamicForm control. The documentation regarding the latter is found here: DynamicForm.

Add some 'Import' statements to your project

1. Open the DemoFormCustomizer.ts file and add the following line near top just underneath the last 'Import' statement:

import { IItem } from '@pnp/sp/items';

2. Now open the Demo.tsx file and add the same line as above again, underneath the last 'Import' statement:

import { IItem } from '@pnp/sp/items';

(Please note, there may be a red squiggly line underneath the statement:

import styles from './Demo.module.scss';

- Just ignore it for now - once the solution is compiled, it will disappear.

3. Still within Demo.tsx also add the following 'Import' statement: 

import { DynamicForm } from "@pnp/spfx-controls-react/lib/DynamicForm";

Use the DynamicForm control

Now we can introduce the DynamicForm control. Within Demo.tsx we can see the existing render() method as follows:

public render(): React.ReactElement<{}> {
    return <div className={styles.demo} />;
  }

Note that it also has a self-closing div tag, so we change that so there is a separate closing div tag then we insert the DynamicForm control as follows:

  public render(): React.ReactElement<{}> {
    return <div className={styles.demo}>
      <DynamicForm
        context={this.props.context as any}
        listId={this.props.context.list.guid.toString()}  
        listItemId={this.props.context.itemId}
        onCancelled={this.props.onClose}
        onBeforeSubmit={async (listItem) => { return false; }}
        onSubmitError={(listItem, error) => { alert(error.message); }}
        onSubmitted={this.props.onSave} />
  </div>;
  }

Notice that it provides a context, and other important values such as the listId and listItemId. In the documentation provided for Dynamic Forms (DynamicForm) - it shows the listId and listItemId hard-coded with a GUID (in quotes) and a number respectively as follows:

 listId={"3071c058-549f-461d-9d73-8b9a52049a80"}  
 listItemId={1}

Instead, we are using:

 listId={this.props.context.list.guid.toString()}  
 listItemId={this.props.context.itemId}

I will outline the configuration steps to reference your own tenant and SharePoint List further down in this post. The DynamicForm will then automatically display items from your list.

Updating the Properties

Still within Demo.tsx, we need to update the properties interface. It currently looks like this:

export interface IDemoProps {
  context: FormCustomizerContext;
  displayMode: FormDisplayMode;
  onSave: () => void;
  onClose: () => void;
}

We need to update onSave as follows:

export interface IDemoProps {
  context: FormCustomizerContext;
  displayMode: FormDisplayMode;
  onSave: (listItemData: any, listItem?: IItem) => void;
  onClose: () => void;
}

Configuring your Form Customizer Extension to use your own tenant and SharePoint List when you debug

Within the config folder open the serve.json file. Within that you have configuration information that you can set, so that it will allow you to see your extension in debug mode within your own tenant and using your own SharePoint list. 

The first block of code tells the extension on what to load when in debug mode (i.e. when you try and debug the solution using the gulp serve command). Here it is:

  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
  "port": 4321,
  "https": true,
  "serveConfigurations": {
    "default": {
      "pageUrl": "https://{tenantDomain}/_layouts/15/SPListForm.aspx",
      "formCustomizer": {
        "componentId": "3175XXXX-XXXX-XXXX-XXXX-XXXXXXXf8d91",
        "PageType": 8,
        "RootFolder": "/sites/mySite/Lists/MyList",
        "properties": {
          "sampleText": "Value"
        }
      }
    },

If you notice, it says default and refers to a PageType of 8. This means it is used by default, and the Page Type of 8 refers to a 'New Form' (i.e. a blank form as per when you are creating a new item). The componentId is the Id of this extension component that you have created, and will be needed later in this post. (NOTE: I have added a few XXXX values in to hide my real component Id guid).

This becomes clear on the next block of code, which begins with demo_NewForm and PageType of 8 again. Then you have a 3rd block which begins with demo_EditForm (PageType of 6) and a 4th block with demo_ViewForm (PageType of 4). These relate to how the form will load, so it will be as an Edit Form and View Form respectively.  Notice that in these last two blocks, there is an extra "ID": 1 entry. This means it will load an item with id = 1 when it shows these forms in debug mode, when showing you an Edit Form or a View Form. You can change that to another id if you wish.

So in each of the four blocks of configuration code, you will need to edit it to use your own tenant and SharePoint list.

E.g.

 "pageUrl": "https://{tenantDomain}/_layouts/15/SPListForm.aspx"

should be changed to something like this (notice it should include the Site also):

"pageUrl": "https://yourtenant.sharepoint.com/yourSiteName/_layouts/15/SPListForm.aspx


Also:

"RootFolder": "/sites/mySite/Lists/MyList",

should be changed to whatever your Site and List names are called, e.g.

"RootFolder": "/sites/yourSiteName/Lists/YourListName",


Previewing your solution in debug mode

Now that the solution has been configured, all we have to do now is do a gulp serve in the terminal and your solution will be compiled and will launch in a browser. You will see the following warning message, just click on the Load debug scripts and your SharePoint list will eventually load in New Form mode, as it's the default configuration. On the first attempt you might need to refresh the page a few times.

Allow debug scripts prompt window
The 'Allow debug scripts?' prompt that you will see

If you want to see the form in an Edit Form mode instead, then instead of gulp serve you will need to use this following command:

 gulp serve --config=demo_EditForm 

Similarly, you can normally use:

 gulp serve --config=demo_ViewForm 

BUT, I've found that the View Form does not work with Dynamic Forms, and it just loads an Edit Form instead. If you have used something other than a Dynamic Form to render the form, then it will be possible to see a View Form.

Additional customisations possible (optional)

In our example, the render() method has been kept very simple, with just the DynamicForm control showing. You could add further elements before or after this control, such as a div element to display a header of some sort for instance.

The DynamicForm control also has other customisations that you can use, such as overriding the default rendering of certain fields with your own custom rendering, hiding certain fields that you do not wish to display on the form, disabling certain fields, what action to perform before submitting the form, and so on. These are mentioned in the documentation: DynamicForm

Deploying your solution

Once you have done all the steps above (the additional customisations are optional), you are ready to deploy to SharePoint Online.

In the terminal console type in the following commands, waiting for each one to complete:

 gulp build 

 gulp bundle --ship 

 gulp package-solution --ship 

Once this is done, you will see a SharePoint folder in your form-customizer solution folder. Within this, you will see a solution folder, once you open that, you will see the package that has been created:   form-customizer.sppkg 

Image of the form-customizer.sppkg package
Image of the form-customizer.sppkg package



This package will now need to be added to your App Catalog site within your SharePoint tenant, within the Apps for SharePoint library. Once you upload it, you will be presented with the dialog box below, where you can choose to have it available to all sites within your organisation (or not). If you do not, then you will need to add this App separately within your desired site.

he dialog box that appears after adding the package to your App Catalog
The dialog box that appears after adding the package to your App Catalog


Associating your form customizer extension to your target list

Once we have deployed our form-customizer solution, we need to associate (or register) it with our target list that needs to use this component in order for it to work as expected. 

This is where a very useful utility developed by Andrew Connell comes into play. It is the SPFx List Form Customizer Manager utility. It is essentially a web part that allows you to select a target list, then apply your form customizer to that list.

Andrew Connell has done a very useful blog post that covers how to use the above utility that he has developed, with some explanation regarding how he utilises the SharePoint REST API. Here it is: Register SPFx list form customizers with the SharePoint REST API
It is definitely well worth a read and contains very useful information. 

The associated video for that blog is here:

To use the utility, you will need to register your email and get a link sent to you, after which you can download the project. Once you've downloaded it you will need to create a separate folder with Andrew's project, then build and deploy that project to your SharePoint Online tenant (use the same commands and steps I mentioned earlier for the form customizer). In my development environment, I had to use an earlier version of node, then I could build and deploy.

Once you have Andrew Connell's utility project deployed, you will need to create a new Site Page (in the same site you wish to use the form customizer), and add the SPFx List Form Customizer Manager web part to your page as shown below. (NOTE: the project contains two web-parts, so for our purpose do not add the SPFx Field Customizer Manager by mistake).

Add the SPFx List Form Customizer Manager web part
Add the SPFx List Form Customizer Manager web part


The web-part utility looks like the image below (I've filled in a few fields as examples):
SPFx List Form Customizer Manager web part utility

So all we have to do is complete the form as follows:

  1. You first select your target List that will be using your form customizer.

  2. The tool then automatically presents all the Content Types used by the List, so we select a Content Type

  3. By default, the Customization scope it toggled to 'On' so that the form customizer will be displayed when using a New form, Edit form and the View form.

    As explained earlier, the Dynamic Form control just displays an Edit form when we try to use it with a View form, so in this instance we can toggle the customization scope to 'Off
    ' so that we apply it to just the New form and Edit form.

    (The View form will be unaffected and will just display the default SharePoint form). 

  4. For our example, select the New form tab to begin with. We now copy and paste the componentId of our form customizer into the List form customizer ID (GUID) field. (You can obtain this from your serve.json file as mentioned earlier in this post. ).

  5. Repeat the process by clicking on the Edit Form and pasting the componentId again.

  6. We now can click Save which will associate/register your form component with the List and Content Type chosen to both the New and Edit forms.

Checking that the form customizer works


If we now go to our target List, we can click on the New button to see our form being rendered similar to my example below. Don't forget your own List will have totally different fields the the example below. Test it by filling out the fields and hitting Save at the bottom.

The rendered customised New form
The rendered customised New form


Once you have done that, you can edit an existing item in your List and see it rendered a bit like my following example:

The rendered customised Edit form

Unregistering the form customizer from your List

If for whatever reason, you wish to unregister the form customizer, so that you revert to using the default SharePoint forms when using the New, Edit or View form, you will need to use the SPFx List Form Customizer Manager again.

You will need to enter the List, Content Type and componentId again as before. However, notice that the Content Type has a cog icon next to it, which signifies that a form customizer already has been applied to it. This is very useful.


The Content Type showing with a cog icon next to it


All we need to do is click on the Remove list form customizers button to unregister your component.

Then you will be back to normal when using your List.

Conclusion

As you can see, we have shown how easily we can override the usual SharePoint Online rendering of List forms with very little code, merely by using the DynamicForm control, which takes each of our fields in the List and renders each one automatically. As mentioned earlier, you can customise even how this is rendered by overriding these fields and writing additional custom code to suit. In my example above, I've not changed the way fields look, but you can certainly use CSS to control how they look and totally customise it to suit your own style and colour-scheme.                                                                                                                                                                         

Useful Links


The idea for using Dynamic Forms was inspired by Paolo Pialorsi and his video is found here:
Episode #213 - Introducing the new Form Customizer Extension of SharePoint Framework





No comments:

Post a Comment