Customizing SharePoint Framework Web Part Properties - Part Five

Introduction
 
In this article, you will learn how to add the dropdown field, bind the values dynamically to SharePoint Framework Web part properties pane, and load the Web part based on the dropdown value selected.
 
In my previous articles, I have introduced the custom properties, explained check box field properties samples and managing multiple pages on the properties pane of SharePoint Framework (SPFx) Web part.
In my SPFx article series, you can learn about SPFx introduction, prerequisites, steps for setting up the environment, and developing and testing the Web parts, using the local environments.
In my previous article, you will have seen how to add a dropdown field to the Web part property pane.

In this article, you will see how to bind the values dynamically to the dropdown field of the Web part properties and load the Web part when a dropdown is selected with the code samples. 
 
Drop down Property Declaration/Definition
 
The values appended to the dropdown field are of type IPropertyPaneDropdownOption. The variable "dropDownOptions" of the same type is declared inside the class.
  1. private dropDownOptions: IPropertyPaneDropdownOption[] =[];  
The properties are defined, using propertyPaneSettings method. The snippet given below shows the defined properties. As you can see, the values are not appended directly to the options, rather variable "dropDownOptions" of type IPropertyPaneDropdownOption is assigned.
  1. protected get propertyPaneSettings(): IPropertyPaneSettings {  
  2.   
  3.   return {  
  4.     pages: [  
  5.       {  
  6.         header: {  
  7.           description: strings.PropertyPaneDescription,  
  8.         },  
  9.         groups: [  
  10.           {  
  11.             groupName:"Lists",  
  12.             groupFields:[  
  13.               PropertyPaneDropdown('DropDownProp',{  
  14.                 label: "Select List To Display on the page",  
  15.                 options:this.dropDownOptions,  
  16.                 isDisabled: false  
  17.               })  
  18.             ]  
  19.           }  
  20.         ]  
  21.       }  
  22.     ]  
  23.   };  
  24. }   
Load/Add Values To Drop Down Property
 
Now, we need to load the list names on to the drop down field dynamically. Basically it means, the variable this.dropDownOptions should be loaded with necessary values (list names as values). To load the values, either onInit() or onPropertyPaneConfigurationStart() methods can be used.
  • onInit() method is executed whenever the page loads.
  • onPropertyPaneConfigurationStart() loads only when the web part property pane is opened.
In this sample, onPropertyPaneConfigurationStart() method will be used. 
 
The snippet given below shows the method. The custom function is written to load SharePoint list names into the dropdown property. Here, this.dropDownOptions property is loaded with the list names.
  1. protected onPropertyPaneConfigurationStart(): void {  
  2.    // Stops execution, if the list values already exists  
  3.   if(this.dropDownOptions.length>0) return;  
  4.   
  5.   // Calls function to append the list names to dropdown  
  6.   this.GetLists();  
  7.   
  8. }  
  9.   
  10. private GetLists():void{  
  11.   // REST API to pull the list names  
  12.   let listresturl: string = this.context.pageContext.web.absoluteUrl + "/_api/web/lists?$select=Id,Title";  
  13.   
  14.   this.LoadLists(listresturl).then((response)=>{  
  15.     // Render the data in the web part  
  16.     this.LoadDropDownValues(response.value);  
  17.   });  
  18. }  
  19. private LoadLists(listresturl:string): Promise<spLists>{  
  20.   return this.context.httpClient.get(listresturl).then((response: Response)=>{  
  21.     return response.json();  
  22.   });  
  23. }  
  24.   
  25. private LoadDropDownValues(lists: spList[]): void{  
  26.   lists.forEach((list:spList)=>{  
  27.     // Loads the drop down values  
  28.     this.dropDownOptions.push({key:list.Title,text:list.Title});  
  29.   });  
  30. }  
Display data on the Web part
 
The data displayed on the Web part is rendered, using render() method. The corresponding custom functions are written and called to display the data on the Web part, which is based on the dropdown value selected. I have explained the same in my previous article (The code can be found the below section). The render() method is called, whenever dropdown property (this.properties.DropDownProp) is changed.  
 
Entire Code 
 
The entire code snippets given below shows the changes made to the various files in the basic Web part project. 
 
IListItemsFormWebPartProps.ts File
  1. export interface IListItemsFormWebPartProps {  
  2.   DropDownProp: string;  
  3. }  
ListItemsFormWebPart.ts File
  1. import {  
  2.   BaseClientSideWebPart,  
  3.   IPropertyPaneSettings,  
  4.   IWebPartContext,  
  5.   PropertyPaneDropdown,  
  6.   IPropertyPaneDropdownOption  
  7.   
  8.   
  9. } from '@microsoft/sp-client-preview';  
  10.   
  11.   
  12. import styles from './ListItemsForm.module.scss';  
  13. import * as strings from 'listItemsFormStrings';  
  14. import { IListItemsFormWebPartProps } from './IListItemsFormWebPartProps';  
  15.   
  16. export interface spListItems{  
  17.   value: spListItem[];  
  18. }  
  19. export interface spListItem{  
  20.   Title: string;  
  21.   id: string;  
  22.   Created: string;  
  23.   Author: {  
  24.     Title: string;  
  25.   };  
  26. }  
  27.   
  28. export interface spList{  
  29. Title:string;  
  30. id: string;  
  31. }  
  32. export interface spLists{  
  33.   value: spList[];  
  34. }  
  35.   
  36.   
  37. export default class ListItemsFormWebPart extends BaseClientSideWebPart<IListItemsFormWebPartProps> {  
  38.   private dropDownOptions: IPropertyPaneDropdownOption[] =[];  
  39.   public constructor(context: IWebPartContext) {  
  40.     super(context);  
  41.   }  
  42.   
  43.   public render(): void {  
  44.     // Render the items in tabular format  
  45.     this.domElement.innerHTML = `  
  46.       <div class="${styles.listItemsForm}">  
  47.         <div class="${styles.Table}">  
  48.           <div class="${styles.Heading}">  
  49.             <div class="${styles.Cell}">Title</div>  
  50.             <div class="${styles.Cell}">Created</div>  
  51.             <div class="${styles.Cell}">Author</div>  
  52.           </div>  
  53.         </div>  
  54.       </div>`;  
  55.       console.log("Render");  
  56.   
  57.       this.LoadData();  
  58.   }  
  59.   
  60.   private LoadData(): void{  
  61.     if(this.properties.DropDownProp != undefined){  
  62.       let url: string = this.context.pageContext.web.absoluteUrl + "/_api/web/lists/getbytitle('"+this.properties.DropDownProp+"')/items?$select=Title,Created,Author/Title&$expand=Author";  
  63.   
  64.   
  65.     this.GetListData(url).then((response)=>{  
  66.       // Render the data in the web part  
  67.       this.RenderListData(response.value);  
  68.     });  
  69.     }  
  70.   
  71.   }  
  72.   
  73.   private GetListData(url: string): Promise<spListItems>{  
  74.     // Retrieves data from SP list  
  75.     return this.context.httpClient.get(url).then((response: Response)=>{  
  76.        return response.json();  
  77.     });  
  78.   }  
  79.   private RenderListData(listItems: spListItem[]): void{  
  80.     let itemsHtml: string = "";  
  81.     // Displays the values in table rows  
  82.     listItems.forEach((listItem: spListItem)=>{  
  83.       itemsHtml += `<div class="${styles.Row}">`;  
  84.       itemsHtml += `<div class="${styles.Cell}"><p>${listItem.Title}</p></div>`;  
  85.         itemsHtml += `<div class="${styles.Cell}"><p>${listItem.Created}</p></div>`;  
  86.         itemsHtml += `<div class="${styles.Cell}"><p>${listItem.Author.Title}</p></div>`;  
  87.   
  88.       itemsHtml += `</div>`;  
  89.     });  
  90.     this.domElement.querySelector("."+styles.Table).innerHTML +=itemsHtml;  
  91.   }  
  92.   
  93.   
  94.   
  95.   protected onPropertyPaneConfigurationStart(): void {  
  96.      // Stops execution, if the list values already exists  
  97.     if(this.dropDownOptions.length>0) return;  
  98.   
  99.     // Calls function to append the list names to dropdown  
  100.     this.GetLists();  
  101.   
  102.   }  
  103.   
  104.   private GetLists():void{  
  105.     // REST API to pull the list names  
  106.     let listresturl: string = this.context.pageContext.web.absoluteUrl + "/_api/web/lists?$select=Id,Title";  
  107.   
  108.     this.LoadLists(listresturl).then((response)=>{  
  109.       // Render the data in the web part  
  110.       this.LoadDropDownValues(response.value);  
  111.     });  
  112.   }  
  113.   private LoadLists(listresturl:string): Promise<spLists>{  
  114.     return this.context.httpClient.get(listresturl).then((response: Response)=>{  
  115.       return response.json();  
  116.     });  
  117.   }  
  118.   
  119.   private LoadDropDownValues(lists: spList[]): void{  
  120.     lists.forEach((list:spList)=>{  
  121.       // Loads the drop down values  
  122.       this.dropDownOptions.push({key:list.Title,text:list.Title});  
  123.     });  
  124.   }  
  125.   
  126.   
  127.   
  128.   protected get propertyPaneSettings(): IPropertyPaneSettings {  
  129.   
  130.     return {  
  131.       pages: [  
  132.         {  
  133.           header: {  
  134.             description: strings.PropertyPaneDescription,  
  135.           },  
  136.           groups: [  
  137.             {  
  138.               groupName:"Lists",  
  139.               groupFields:[  
  140.                 PropertyPaneDropdown('DropDownProp',{  
  141.                   label: "Select List To Display on the page",  
  142.                   options:this.dropDownOptions,  
  143.                   isDisabled: false  
  144.                 })  
  145.               ]  
  146.             }  
  147.           ]  
  148.         }  
  149.       ]  
  150.     };  
  151.   }  
  152. }  
ListItemsForm.module.scss File
  1. .listItemsForm {  
  2.   .container {  
  3.     max-width: 700px;  
  4.     margin: 0px auto;  
  5.     box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);  
  6.   }  
  7.   
  8.   .row {  
  9.     padding: 20px;  
  10.   }  
  11.   
  12.   .listItem {  
  13.     max-width: 715px;  
  14.     margin: 5px auto 5px auto;  
  15.     box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);  
  16.   }  
  17.   
  18.   .button {  
  19.     text-decoration: none;  
  20.   }  
  21.   .listItemTitle{  
  22.     font-size: large;  
  23.     color: darkblue;  
  24.   }  
  25.   .listItemProps{  
  26.     font-size: small;  
  27.   }  
  28.   
  29.   .Table  
  30.     {  
  31.         display: table;  
  32.     }  
  33.     .Title  
  34.     {  
  35.         display: table-caption;  
  36.         text-align: center;  
  37.         font-weight: bold;  
  38.         font-size: larger;  
  39.     }  
  40.     .Heading  
  41.     {  
  42.         display: table-row;  
  43.         font-weight: bold;  
  44.         text-align: center;  
  45.     }  
  46.     .Row  
  47.     {  
  48.         display: table-row;  
  49.     }  
  50.     .Cell  
  51.     {  
  52.         display: table-cell;  
  53.         border: solid;  
  54.         border-width: thin;  
  55.         padding-left: 5px;  
  56.         padding-right: 5px;  
  57.     }  
  58. }  
mystrings.d.ts File
  1. declare interface IListItemsFormStrings {  
  2.   PropertyPaneDescription: string;  
  3.   BasicGroupName: string;  
  4.   DescriptionFieldLabel: string;  
  5.   TitleFieldLabel: string;  
  6.   BasicInfo: string;  
  7. }  
  8.   
  9. declare module 'listItemsFormStrings' {  
  10.   const strings: IListItemsFormStrings;  
  11.   export = strings;  
  12. }  
en-us.js File
  1. define([], function() {  
  2.   return {  
  3.     "PropertyPaneDescription""Config Web Part",  
  4.     "BasicGroupName""Group Name",  
  5.     "DescriptionFieldLabel""Description Field",  
  6.     "BasicInfo""Basic Information"  
  7.   }  
  8. });   
Summary
 
Thus, you have learned how to add dropdown field to the Web part property pane, bind dropdown values dynamically and load the Web part, which is based on the selected dropdown property.