Question

I was playing around with the SharePoint framework and I was trying to get the web part to load SharePoint lists via a promise.

First I noticed that await and async are not supported (probably due to ES version).

When I tried to implement a a promise method and just return it, the properties pane was not compiling. The following method is parsing the lists from the sample (https://github.com/SharePoint/sp-dev-docs/wiki) to drop down collection objects (key and text properties):

    private _getPropertiesPanePromise(): Promise<ICustomProperties> {
    return this._getMockListData().then((response) => {
      var listOptions: ICustomProperties = this._getListObjectsForProps(response.value);
      return listOptions;
    }) as Promise<ICustomProperties>;
  }

Has anyone found a way to load SharePoint data in the SPFx properties pane at the moment?

Was it helpful?

Solution

The easiest way to do this would be to load the data in your OnInit() method, and then reference it in your property pane. That won't work if you need the data to be more reactive (ie, you first select a list, then you select a list item), but if you are simply showing the current set of lists in the current web (for example), that should work.

We need to write docs/examples of how to do this in the actual property pane for cascading type scenarios.

Specifically - do the following (building on the Tutorial 2 in the wiki -https://github.com/SharePoint/sp-dev-docs/wiki/HelloWorld,-Talking-to-SharePoint )

1 - Add

IPropertyPaneDropdownOption 

to your imports from sp-client-preview

2 - Add the following code

private _dropdownOptions: IPropertyPaneDropdownOption[] = [];
public onInit<T>(): Promise<T> {
  this._getListData()
    .then((response) => {

      this._dropdownOptions = response.value.map((list: ISPList) => {
        return {
          key: list.Id,
          text: list.Title
        };
      });
    });
    return Promise.resolve();
}

3 - Update the entry in propertyPaneSettings for the dropdown as follows:

            PropertyPaneDropdown('test2', {
              label: 'Dropdown',
              options: this._dropdownOptions
            }),

OTHER TIPS

This issue was posted as an issue in the SPFx project and an answer was provided using existing API functionality.

https://github.com/SharePoint/sp-dev-docs/wiki/Async-data-fetch-in-the-property-pane

The gist is, ignore OnInit, and add the following code, tailored to your needs to the propertyPaneSettings method in your webpart.

if (!this.listsFetched) {
this._getListData()
.then((response) => {
  this._dropdownOptions = response.value.map((list: ISPList) => {
    return {
      key: list.Id,
      text: list.Title
    };
  });
  this.listsFetched = true;
  this.configureStart();
});
}

There are a few caveats, refer to the github wiki article for further details.

The approach for loading data in propertypane is to leverage OnInit function to load initial data for the control. since OnInit return a Promise, you can do the following:

    protected onInit<T>(): Promise<void> {
    return new Promise<void>((resolve, reject) => {
        this._listService.getListsInfo()
            .then((response: ISPListInfo[]) => {
                this._dropdownListOptions = response.map((list: ISPListInfo) => {
                    return {
                        key: list.listTitle,
                        text: list.listTitle
                    };
                });
                resolve();
            });
    });
    }

If you have multiple controls and those controls have dependency based on the each other, you can load the second control's data in onPropertyChanged method like the following:

    protected onPropertyChanged(propertyPath: string, oldValue: any, newValue: any): void {
    if (propertyPath === "selListTitle") {
        this._listService.getListFieldsInfo(this.properties.selListTitle)
            .then((response: ISPListFieldInfo[]) => {
                this._dropdownXFieldOptions = response.map((field: ISPListFieldInfo) => {
                    return {
                        key: field.fieldTitle,
                        text: field.fieldTitle
                    };
                });
                this._dropdownYFieldOptions = response.map((field: ISPListFieldInfo) => {
                    return {
                        key: field.fieldTitle,
                        text: field.fieldTitle
                    };
                });
                //force the property panel to refresh
                this.configureStart(true);
            });
    }

there are couple tricks here. First you need to check the propertyPath for the control you are listening and load your data. Second, once you have data loaded from your service, you need to call this.configureStart(true) to refresh the PropertyPane. the parameter is to indicate you just want to refresh only. So you service can support Primise, all you need to do is to call configureStart method.

Thoughts: Since the data binding is very popular for client-side application development, I am surprise to see that the SharePoint Framework doesn't support the data binding or leverage some existing data binding library like Angular or Knockout.

I hope it helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top