Click here to Skip to main content
15,881,852 members
Articles / Productivity Apps and Services / Sharepoint

Explaining PropertyPaneAsyncDropdown

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
12 Jan 2018CPOL3 min read 6K   16  
About PropertyPaneAsyncDropdown

Preface

I recently started working on SpFX framework for SharePoint client side development. I was going through SpFx Pnp samples. While samples are great, online documentation is not. It is verbose yet cryptic. I thought I'd break the samples down for my own learning & write these blogs to simplify for anyone else who picks up these samples to get his/her feet wet with SpFX. There might be a series of posts in coming days if don't lose interest or don't find anything better to do 😃

SpFx samples are available here: https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples .

We'd look into react related samples.

PropertyPaneAsyncPaneDropdown is there in PnP samples as an example of asynchronously populated "select" control in property pane. There are 4 typeScript interfaces in play and we should discuss them first.

Image 1

IPropertyPaneAsyncDropdownProps

First one up is IPropertyPaneAsyncDropdownProps. The purpose of this interface is to pass information from webpart file to the custom control, i.e., PropertyPaneAsyncDropdown. Interface looks like:

JavaScript
export interface IPropertyPaneAsyncDropdownProps 
{ 
label : string ;
loadOptions : () => Promise < IDropdownOption []>;
onPropertyChange : ( propertyPath : string , newValue : any ) => void ;
selectedKey : string | number ;
disabled ?: boolean ;
}
  • label: Label of the property in property pane.
  • loadOptions: Method to fetch options for the dropdown, in our case method to fetch list information from Sharepoint so that user can select a list name in property pane.
  • onPropertyChange: Method to execute when user selects an item in the dropdown, i.e., when user selects a list.
  • selectedKey: Value from the selected option in dropdown. In our case, it is the list Url of selected list.
  • disabled: We are not using it but could be used to render the control disabled.

IPropertyPaneAsyncDropdownInternalProps

Second up is IPropertyPaneAsyncDropdownInternalProps. This interface extends IPropertyPaneAsyncDropdownProps (our own) and IPropertyPaneCustomFieldProps (imported from @microsoft/sp-webpart-base) and it doesn't implement any attribute of its own. We need an instance of IPropertyPaneCustomFieldProps to work with a custom property control & IPropertyPaneAsyncDropdownInternalProps is an instance of one. Besides the attributes we defined in our IPropertyPaneAsyncDropdownProps, we'd be using onRender attribute (inherited from IPropertyPaneCustomFieldProps). 
key is another mandatory attribute from IPropertyPaneCustomFieldProps & we'll set it.
Before we discuss the remaining two interfaces, let's dive into the custom property itself.

PropertyPaneAsyncDropdown

This class implements IPropertyPaneField<IPropertyPaneAsyncDropdownProps>, which dictates that our class should have these three attributes (which we do):

JavaScript
public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
public targetProperty: string;
public properties: IPropertyPaneAsyncDropdownInternalProps;

Well, as per the dictation of implemented interface, properties attribute should have type IPropertyPaneAsyncDropdownProps, but remember IPropertyPaneAsyncDropdownInternalProps extends IPropertyPaneAsyncDropdownProps so we are OK here.

Now, look at the constructor:

JavaScript
constructor ( targetProperty :  string ,  properties :  IPropertyPaneAsyncDropdownProps ) 
{
this . targetProperty  =  targetProperty ; 
this . properties  =  
{ 
key :  properties . label , 
label :  properties . label , 
loadOptions :  properties . loadOptions , 
onPropertyChange :  properties . onPropertyChange , 
selectedKey :  properties . selectedKey , 
disabled :  properties . disabled , 
onRender :  this . onRender . bind ( this ) 
}; 
}

Remember, we create the instance of this class from webpart itself so we pass the property name from there, also we pass an instance of IPropertyPaneAsyncDropdownProps from webpart code. key and onRender are two attributes which IPropertyPaneAsyncDropdownInternalProps inherits from IPropertyPaneCustomFieldProps and we set key to label and onRender to a locally defined function.

IAsyncDropdownProps

We will discuss this interface in context to where it is used in PropertyPaneAsyncDropdown class in onRender method.

C#
private   onRender ( elem :  HTMLElement ):  void   
{ 
if  (! this . elem ) 
{ 
this . elem  =  elem ; 
} 
 
const   element :  React . ReactElement < IAsyncDropdownProps > = 
React . createElement ( AsyncDropdown , 
{ 
label:   this . properties . label , 
loadOptions:   this . properties . loadOptions , 
onChanged:   this . onChanged . bind ( this ), 
selectedKey:   this . properties . selectedKey , 
disabled:   this . properties . disabled , 
// required to allow the component to be re-rendered by   
//calling this.render() externally   
stateKey:   new   Date (). toString () 
}); 
ReactDom . render ( element ,  elem ); 
} 

stateKeyonChanged are worth discussing. We set stateKey to current time so that every time user opens the property pane, stateKey has a new value. We'd use this fact to reload the select options every time user opens the property pane.

onChanged is set to a locally defined function as:

JavaScript
private onChanged(option: IDropdownOption, index?: number): void {
this.properties.onPropertyChange(this.targetProperty, option.key);
}

All this function does is it calls the method passed by the web part.

ListViewWebPart

This is the webpart file itself. We should look the property setup here.

JavaScript
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration
{
return 
{
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
new PropertyPaneAsyncDropdown('listUrl', {
label: strings.ListFieldLabel,
loadOptions: this.loadLists.bind(this),
onPropertyChange: this.onListChange.bind(this),
selectedKey: this.properties.listUrl
})
]
}
]
}
]
};
}

We should look at the onPropertyChange function here:

JavaScript
private onListChange(propertyPath: string, newValue: any): void
{
const oldValue: any = get(this.properties, propertyPath);
if (oldValue !== newValue)
{
//this.properties.fields = null;
}
// store new value in web part properties
update( this.properties, propertyPath, (): any => newValue );
// refresh property Pane
this.context.propertyPane.refresh();
// refresh web part
this.render();
}

Whenever the user selects a new value in the dropdown, we need to update the webpart property explicitly via "update" call (imported from @microsoft/sp-lodash-subset).

There is one more file "AsyncDropdown.tsx" which plays an important role but this file, while it's long, is also self explanatory.

Here is a link to the src folder for this webpart.

My next step would be to introduce a dependent cascaded drop down control (to select list columns). Eventually, I'd render a list view of selected columns.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --