I am trying to follow the same steps here: https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/use-cascading-dropdowns-in-web-part-properties
But I wanted to do it with Folders instead of items.
Here's the webpart class I have right now:
export default class FolderNavigator extends BaseClientSideWebPart<IFolderNavigatorWebPartProps> {
private lists: IPropertyPaneDropdownOption[];
private folders: IPropertyPaneDropdownOption[];
private listsDropdownDisabled: boolean = true;
private foldersDropdownDisabled: boolean = true;
public onInit(): Promise<void> {
return super.onInit().then(_ => {
sp.setup({
spfxContext: this.context
})
});
}
private async loadLists(): Promise<IPropertyPaneDropdownOption[]> {
let listsRequest = sp.web.lists.filter('Hidden eq false').get()
let lists = await listsRequest
let options: IPropertyPaneDropdownOption[] = [];
lists.forEach(list => {
options.push({
key: list.Title,
text: list.Title
})
})
return options;
}
//Here everytime the property pane loads, this.lists and this.folders = undefined
protected async onPropertyPaneConfigurationStart(): Promise<void> {
this.listsDropdownDisabled = !this.lists;
this.foldersDropdownDisabled = !this.folders;
if (this.lists) {
return;
}
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'lists');
let listOptions = await this.loadLists()
this.lists = listOptions;
this.listsDropdownDisabled = false;
this.context.propertyPane.refresh();
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.render();
}
private async loadAvailablefolders(listName: string): Promise<IPropertyPaneDropdownOption[]> {
let availablefolders = sp.web.lists.getByTitle(listName).rootFolder.folders
.filter('ListItemAllFields/Id ne null')
.expand('ListItemAllFields')
.get()
let folders = await availablefolders
let options: IPropertyPaneDropdownOption[] = []
console.log(folders)
folders.forEach(folder => {
options.push({
key: folder.Name,
text: folder.Name
})
})
return options;
}
protected async onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): Promise<void> {
if (propertyPath === 'listName' && newValue) {
this.listsDropdownDisabled = true;
let folders = await this.loadAvailablefolders(newValue)
this.folders = folders
this.foldersDropdownDisabled = false
this.listsDropdownDisabled = false
this.context.propertyPane.refresh();
this.render()
}
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
public render(): void {
const element: React.ReactElement<INavigatorProps> = React.createElement(
Navigator,
{
description: this.properties.listName
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneDropdown('listName', {
label: strings.ListNameLabel,
options: this.lists,
disabled: this.listsDropdownDisabled
}),
PropertyPaneDropdown('folderName', {
label: strings.FolderNameLabel,
options: this.folders,
disabled: this.foldersDropdownDisabled
})
]
}
]
}
]
};
}
}
Whenever the function: onPropertyPaneConfigurationStart runs, this.lists and this.folders values are undefined
Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.
This is by design... it's because you aren't setting the values of the drop downs in the property pane. Look at the selectedKey property of the IPropertyPaneDropdownProps interface. This should be the key of the item you want to have selected.
@andrewconnell Thanks for your response. I tried to modify the property pane code to include the selectedkey property like this:
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneDropdown('listName', {
label: strings.ListNameLabel,
options: this.lists,
disabled: this.listsDropdownDisabled,
selectedKey: this.properties.listName
}),
PropertyPaneDropdown('folderName', {
label: strings.FolderNameLabel,
options: this.folders,
disabled: this.foldersDropdownDisabled,
selectedKey: this.properties.folderName
})
]
}
]
}
]
};
}
and I updated the onPropertyPaneFieldChanged method to update these properties whenever I change the dropdown list value, like
this:
protected async onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): Promise<void> {
if (propertyPath === 'listName' && newValue) {
this.listsDropdownDisabled = true;
let folders = await this.loadAvailablefolders(newValue)
this.folders = folders
this.foldersDropdownDisabled = false
this.listsDropdownDisabled = false
this.properties[propertyPath] = newValue
this.context.propertyPane.refresh();
this.render()
}
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
I am confused about two things, am I not following the steps here correctly: https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/use-cascading-dropdowns-in-web-part-properties ?
Second thing is, when I change the selected item in a dropdown list, I save its value in this.properties[propName], doesn't this save to the selectedkey of the property according to my code?
The examples I am reading online they show how to create the webpart property, but they don't show how to actually save the prop, and the values would be gone after the refresh.
What am I doing wrong here?
First, this is not necessary:
protected async onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): Promise<void> {
...
this.properties[propertyPath] = newValue
...
}
I think you're doing this because you don't understand how public properties on the web part are declared & persisted... I'm making that assumption from when you said:
The examples I am reading online they show how to create the webpart property, but they don't show how to actually save the prop, and the values would be gone after the refresh.
SPFx automatically saves the value of the public property you define in the interface of the web part & when you bind a property pane control to that property.
How? It does that automatically because you've bound to it by name here:
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
groups: [
{
groupFields: [
PropertyPaneDropdown('listName', {..}),
PropertyPaneDropdown('folderName', {..})
]
}
]
}
]
};
}
_Actually..._ where's the interface that defines the public properties for your web part? That's usually in the same file & declared immediately above the web part declaration. That tells SharePoint what public properties are on your web part. You should have something like:
public interface IFolderNavigatorWebPartProps {
listName: string;
folderName: string;
}
Second... as for that article you're referencing, I don't see anything in it where it is demonstrating setting the initial state of the dropdown selectors. The project it references at the top is a more complex version of that article as it shows how to create custom property pane controls, but that's now what you're trying to do.
BTW... I wouldn't use the title as the key... use the list's ID. Someone can rename the list and the selections break for existing instances of the web parts, but the IDs never change.
Thank you for clearing up the confusion. Now it's clear. Very much appreciated @andrewconnell
Issues that have been closed & had no follow-up activity for at least 7 days are automatically locked. Please refer to our wiki for more details, including how to remediate this action if you feel this was done prematurely or in error: Issue List: Our approach to locked issues
Most helpful comment
First, this is not necessary:
I think you're doing this because you don't understand how public properties on the web part are declared & persisted... I'm making that assumption from when you said:
SPFx automatically saves the value of the public property you define in the interface of the web part & when you bind a property pane control to that property.
How? It does that automatically because you've bound to it by name here:
_Actually..._ where's the interface that defines the public properties for your web part? That's usually in the same file & declared immediately above the web part declaration. That tells SharePoint what public properties are on your web part. You should have something like:
Second... as for that article you're referencing, I don't see anything in it where it is demonstrating setting the initial state of the dropdown selectors. The project it references at the top is a more complex version of that article as it shows how to create custom property pane controls, but that's now what you're trying to do.
BTW... I wouldn't use the title as the key... use the list's ID. Someone can rename the list and the selections break for existing instances of the web parts, but the IDs never change.