Thursday, 12 January 2017

Working With Cascading Dropdowns In SPFx Webpart Propeties

Views
In this post, you will learn how to populate cascading drop down options in SharePoint Framework web part properties pane.
You will see how to populate cascading dropdown fields with dynamic SharePoint list content. I have used two dropdowns in this sample.

Declare Drop down Fields/Properties 


The drop down values appended to the field is of type IPropertyPaneDropdownOption. The variables "listDropDownOptions" and "itemDropDownOptions" of same type are declared inside the class.
The below snippet shows the property declaration.
  1. private listDropDownOptions: IPropertyPaneDropdownOption[] =[];  
  2. private itemDropDownOptions: IPropertyPaneDropdownOption[] = [];   

Define Properties 


The properties are defined using propertyPaneSettings() method. The below snippet shows the properties defined.
  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('listDropDown',{  
  14.                 label: "Select List To Display on the page",  
  15.                 options:this.listDropDownOptions,  
  16.                 isDisabled: false  
  17.               }),  
  18.               PropertyPaneDropdown('ItemsDropDown',{  
  19.                 label: "Select Item to display",  
  20.                 options: this.itemDropDownOptions,  
  21.                 isDisabled: false  
  22.   
  23.               })  
  24.             ]  
  25.           }  
  26.         ]  
  27.       }  
  28.     ]  
  29.   };  
  30. }  
Note - There are two properties defined. One dropdown is for list source and the other dropdown is for listing down the items of the list. As you can see, the values are not appended directly, rather variable of type IPropertyPaneDropdownOption is assigned. 

Load First Dropdown (List Dropdown) 


Initially, on the property pane load, all the lists available in the SharePoint site should be listed in the list dropdown. Next, we need to load the list names on the dropdown field dynamically.
To load the values, onPropertyPaneConfigurationStart method is used. It loads only when the property pane is opened. So, this method will be used in the current sample.
The below snippet shows the methods to load the list names into list dropdown. The custom function is written to load the SharePoint list names into the dropdown property. Here, this.listDropDownOptions property is loaded with the list names, which will reflect in the list dropdown property.
  1. protected onPropertyPaneConfigurationStart(): void {  
  2.   // loads list name into list dropdown  
  3.   this.GetLists();  
  4.   
  5. }  
  6.   
  7. private GetLists():void{  
  8.   // REST API to pull the list names  
  9.   let listresturl: string = this.context.pageContext.web.absoluteUrl + "/_api/web/lists?$select=Id,Title";  
  10.   
  11.   this.LoadLists(listresturl).then((response)=>{  
  12.     // Render the data in the web part  
  13.     this.LoadDropDownValues(response.value);  
  14.   });  
  15. }  
  16.   
  17. private LoadLists(listresturl:string): Promise<spLists>{  
  18.   // Call to site to get the list names  
  19.   return this.context.httpClient.get(listresturl).then((response: Response)=>{  
  20.     return response.json();  
  21.   });  
  22. }  
  23.   
  24. private LoadDropDownValues(lists: spList[]): void{  
  25.   lists.forEach((list:spList)=>{  
  26.     // Loads the drop down values  
  27.     this.listDropDownOptions.push({key:list.Title,text:list.Title});  
  28.   });  
  29. }   


Load Second Dropdown (Items Dropdown)  


Then, once the list name is selected, the items dropdown property should be populated. This can be done by overriding onPropertyChange method. The method takes two parameters (property path and new value). The function should be executed only when the list dropdown property is changed.
The below snippet shows the methods to load the items (item Title field) into list dropdown. The custom function is written to load the SharePoint item titles into the items dropdown property. Here, this.itemsDropDownOptions property is loaded with the item titles, which will reflect in the item dropdown property.
  1. protected onPropertyChange(propertyPath: string, newValue: any):void{  
  2.   if(propertyPath === "listDropDown"){  
  3.     // Change only when drop down changes  
  4.     super.onPropertyChange(propertyPath,newValue);  
  5.     // Clears the existing data  
  6.     this.properties.ItemsDropDown = undefined;  
  7.     this.onPropertyChange('ItemsDropDown'this.properties.ItemsDropDown);  
  8.     // Get/Load new items data  
  9.     this.GetItems();  
  10.   }  
  11.   else {  
  12.     // Render the property field  
  13.     super.onPropertyChange(propertyPath, newValue);  
  14.   }  
  15. }  
  16.   
  17. private GetItems(): void{  
  18.   // Retrives Items from SP List  
  19.   if(this.properties.listDropDown != undefined){  
  20.     let url: string = this.context.pageContext.web.absoluteUrl + "/_api/web/lists/getbytitle('"+this.properties.listDropDown+"')/items?$select=ID,Title,Created,Author/Title&$expand=Author";  
  21.   
  22.     this.GetItemsDropDown(url).then((response)=>{  
  23.       // Loads in to drop down field  
  24.       this.LoadItemsDropDown(response.value);  
  25.     });  
  26.   }  
  27. }  
  28.   
  29. private GetItemsDropDown(listresturl:string): Promise<spListItems>{  
  30.   // Call to list to get the items  
  31.   return this.context.httpClient.get(listresturl).then((response: Response)=>{  
  32.     return response.json();  
  33.   });  
  34. }  
  35.   
  36. private LoadItemsDropDown(listitems: spListItem[]): void{  
  37.   // Populates drop down values  
  38.   this.itemDropDownOptions = [];  
  39.   if(listitems != undefined){  
  40.     listitems.forEach((listItem:spListItem)=>{  
  41.       this.itemDropDownOptions.push({key:listItem.ID,text:listItem.Title});  
  42.     });  
  43.   }  
  44. }   


Render Web Part  


The data displayed on the web part is rendered using render method. The web part should be rendered based on the values selected from two drop downs. The custom functions are written inside render() method to display the list items based on the list name and items selected from the drop downs.
The below snippet shows the functions to render the data on the web part.
  1. public render(): void {  
  2.   // Render the items in tabular format  
  3.   this.domElement.innerHTML = `  
  4.     <div class="${styles.listItemsForm}">  
  5.       <div class="${styles.Table}">  
  6.         <div class="${styles.Heading}">  
  7.           <div class="${styles.Cell}">Title</div>  
  8.           <div class="${styles.Cell}">Created</div>  
  9.           <div class="${styles.Cell}">Author</div>  
  10.         </div>  
  11.       </div>  
  12.     </div>`;  
  13.     console.log("Render");  
  14.   
  15.     this.LoadData();  
  16. }  
  17.   
  18. private LoadData(): void{  
  19.   if(this.properties.listDropDown != undefined && this.properties.ItemsDropDown != undefined){  
  20.     let url: string = this.context.pageContext.web.absoluteUrl + "/_api/web/lists/getbytitle('"+this.properties.listDropDown+"')/items?$select=Title,Created,Author/Title&$expand=Author&$filter=ID eq "+this.properties.ItemsDropDown;  
  21.     this.GetListData(url).then((response)=>{  
  22.       // Render the data in the web part  
  23.       this.RenderListData(response.value);  
  24.     });  
  25.   }  
  26. }  
  27.   
  28. private GetListData(url: string): Promise<spListItems>{  
  29.   // Retrieves data from SP list  
  30.   return this.context.httpClient.get(url).then((response: Response)=>{  
  31.      return response.json();  
  32.   });  
  33. }  
  34.   
  35. private RenderListData(listItems: spListItem[]): void{  
  36.   let itemsHtml: string = "";  
  37.   // Displays the values in table rows  
  38.   listItems.forEach((listItem: spListItem)=>{  
  39.     itemsHtml += `<div class="${styles.Row}">`;  
  40.     itemsHtml += `<div class="${styles.Cell}"><p>${listItem.Title}</p></div>`;  
  41.       itemsHtml += `<div class="${styles.Cell}"><p>${listItem.Created}</p></div>`;  
  42.       itemsHtml += `<div class="${styles.Cell}"><p>${listItem.Author.Title}</p></div>`;  
  43.   
  44.     itemsHtml += `</div>`;  
  45.   });  
  46.   this.domElement.querySelector("."+styles.Table).innerHTML +=itemsHtml;  
  47. }  


Interfaces  


The interfaces required for the sample can be found below.
  1. export interface spListItems{  
  2.   value: spListItem[];  
  3. }  
  4. export interface spListItem{  
  5.   Title: string;  
  6.   ID: string;  
  7.   Created: string;  
  8.   Author: {  
  9.     Title: string;  
  10.   };  
  11. }  
  12.   
  13. export interface spList{  
  14. Title:string;  
  15. id: string;  
  16. }  
  17. export interface spLists{  
  18.   value: spList[];  
  19. }  
The below snapshot shows the web part with the cascading dropdown fields on SPFx web part properties pane.


Summary 


Thus, you have learned how to build the cascading dropdown and populate the values dynamically on the SharePoint Framework web part properties pane.