SPFx Cascading Dropdown In Property Pane

Introduction

 
In SPFx property pane configuration, many times we are required to filter records based on another property pane controls. In this article, we will learn how to cascade a dropdown in the property pane without creating any custom control.
 

Scenario

 
For example, there are multiple lists on a Sharepoint site, and based on the selection of list we want to get fields of the selected list. So in this type of scenario, we require cascading dropdowns.
 
In this example, we will use PropertyFieldListPicker to select the list and will use PropertyFieldMultiSelect to select the list's fields. And here we will use PnP js to get fields of the selected list and then filter it based on list selection, as shown below:
 
SPFx Cascading Dropdown In Property Pane
 
Let's see the step-by-step implementation.
 

Implementation 

  • Open a command prompt
  • Move to the path where you want to create a project
  • Create a project directory using:
  1. md directory-name  
Move to the above-created directory using:
  1. cd directory-name  
Now execute the below command to create an SPFx solution:
  1. yo @microsoft/sharepoint  
It will ask some questions, as shown below:
 
SPFx Setup
 
After a successful installation, we can open a project in any source code tool. Here, I am using VS code, so I will execute a command:
  1. code .  
Now we will install pnpjs and pnp-spfx-property-controls as shown below:
  1. npm install @pnp/sp --save  
  2. npm install @pnp/spfx-property-controls --save --save-exact  
Now go to the src > webparts > webpart > components > I{webpartname}Props.ts file,
 
Here, we will declare the properties for a list, the fields and context to get SharePoint context are shown below:
  1. import { WebPartContext } from "@microsoft/sp-webpart-base";  
  2.   
  3. export interface IPnpCascadingProps {  
  4.   description: string;  
  5.   context: WebPartContext;  
  6.   list: string,  
  7.   fields: string[]  
  8. }  
Now create a folder called service inside a webpart folder, and then create a file called service.ts in this folder. In this file, we will create a SPService to get fields for the selected list.
  1. import { WebPartContext } from "@microsoft/sp-webpart-base";  
  2. import { sp } from "@pnp/sp/presets/all";  
  3.   
  4. export class SPService {  
  5.     constructor(private context: WebPartContext) {  
  6.         sp.setup({  
  7.             spfxContext: this.context  
  8.         });  
  9.     }  
  10.   
  11.     public async getFields(selectedList: string): Promise<any> {  
  12.         try {  
  13.             const allFields: any[] = await sp.web.lists  
  14.                 .getById(selectedList).  
  15.                 fields.  
  16.                 filter("Hidden eq false and ReadOnlyField eq false").get();;  
  17.             return allFields;  
  18.         }  
  19.         catch (err) {  
  20.             Promise.reject(err);  
  21.         }  
  22.     }  
  23. }  
Now go to the {webpartName}webpart.ts file. here we will create the property pane controls so will call the method to get fields and bind it with a multi-select dropdown field.
 
Import all the dependencies, as shown below:
  1. import * as React from 'react';  
  2. import * as ReactDom from 'react-dom';  
  3. import { Version } from '@microsoft/sp-core-library';  
  4. import {  
  5.   IPropertyPaneConfiguration,  
  6.   PropertyPaneTextField,  
  7.   IPropertyPaneDropdownOption  
  8. } from '@microsoft/sp-property-pane';  
  9. import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';  
  10.   
  11. import * as strings from 'PnpCascadingWebPartStrings';  
  12. import PnpCascading from './components/PnpCascading';  
  13. import { IPnpCascadingProps } from './components/IPnpCascadingProps';  
  14. import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';  
  15. import { PropertyFieldMultiSelect } from '@pnp/spfx-property-controls/lib/PropertyFieldMultiSelect';  
  16. import { sp } from '@pnp/sp';  
  17. import { SPService } from '../service/Service';   
Declare the list and field inside props interface as shown below:
  1. export interface IPnpCascadingWebPartProps {  
  2.   description: string;  
  3.   lists: string;  
  4.   fields: string[];  
  5. }  
Now declare the service and dropdown option in class as shown below:
  1. private _services: SPService = null;  
  2. private _listFields: IPropertyPaneDropdownOption[] = [];  
Create a function to get all fields. Here we will call a service as shown below:
  1. public async getListFields() {  
  2.     if (this.properties.lists) {  
  3.       let allFields = await this._services.getFields(this.properties.lists);  
  4.       (this._listFields as []).length = 0;  
  5.       this._listFields.push(...allFields.map(field => ({ key: field.InternalName, text: field.Title })));  
  6.     }  
  7.   }  
Create an OnInit() method to get sharepoint context and bind service and methods:
  1. public onInit(): Promise<void> {  
  2.     return super.onInit().then(_ => {  
  3.       sp.setup({  
  4.         spfxContext: this.context  
  5.       });  
  6.       this._services = new SPService(this.context);  
  7.       this.getListFields = this.getListFields.bind(this);  
  8.     });  
  9.   }  
Create a method to change field value based on list selection.
  1. private listConfigurationChanged(propertyPath: string, oldValue: any, newValue: any) {  
  2.    console.log("LIST FIELDS:"this._listFields);  
  3.    if (propertyPath === 'lists' && newValue) {  
  4.      this.properties.fields = [];  
  5.      this.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);  
  6.      this.context.propertyPane.refresh();  
  7.    }  
  8.    else {  
  9.      super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);  
  10.    }  
  11.  }  
Create a property pane controls and map the values as shown below:
  1. protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {  
  2.     this.getListFields();  
  3.     return {  
  4.       pages: [  
  5.         {  
  6.           header: {  
  7.             description: strings.PropertyPaneDescription  
  8.           },  
  9.           groups: [  
  10.             {  
  11.               groupName: strings.BasicGroupName,  
  12.               groupFields: [  
  13.                 PropertyPaneTextField('description', {  
  14.                   label: strings.DescriptionFieldLabel  
  15.                 }),  
  16.                 PropertyFieldListPicker('lists', {  
  17.                   label: 'Select a list',  
  18.                   selectedList: this.properties.lists,  
  19.                   includeHidden: false,  
  20.                   orderBy: PropertyFieldListPickerOrderBy.Title,  
  21.                   disabled: false,  
  22.                   baseTemplate: 100,  
  23.                   onPropertyChange: this.listConfigurationChanged.bind(this),  
  24.                   properties: this.properties,  
  25.                   context: this.context,  
  26.                   onGetErrorMessage: null,  
  27.                   key: 'listPickerFieldId',  
  28.                 }),  
  29.                 PropertyFieldMultiSelect('fields', {  
  30.                   key: 'multiSelect',  
  31.                   label: "Multi select list fields",  
  32.                   options: this._listFields,  
  33.                   selectedKeys: this.properties.fields  
  34.                 })  
  35.               ]  
  36.             }  
  37.           ]  
  38.         }  
  39.       ]  
  40.     };  
  41.   }  
Move to the webpart.tsx file and will print the selected list and field value to verify the result.
  1. import * as React from 'react';  
  2. import styles from './PnpCascading.module.scss';  
  3. import { IPnpCascadingProps } from './IPnpCascadingProps';  
  4. import { escape } from '@microsoft/sp-lodash-subset';  
  5.   
  6. export default class PnpCascading extends React.Component<IPnpCascadingProps, {}> {  
  7.   public render(): React.ReactElement<IPnpCascadingProps> {  
  8.     return (  
  9.       <div className={styles.pnpCascading}>  
  10.         <p>Selected List: {this.props.list}</p>  
  11.         <p>Selected Fields: {this.props.fields}</p>  
  12.       </div>  
  13.     );  
  14.   }  
  15. }  
Output
 
SPFx Cascading Dropdown In Property Pane
 
Find the complete source code here.
 

Summary

In this article, we have seen how to implement cascading dropdown in property pane configuration using pnp js and reusable property pane controls.
 
I hope this helps.
 
Sharing is caring!!