5

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?

3 Answers 3

7

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
            }),
1
  • 1
    I believe I got the hang of it. Thanks for the directions @PatMill_MSFT. I am sharing the code for the rest. I have managed to to load properties on changing other values. 1. I have added another interface for list views. export interface ISPViews { value: ISPView[]; } export interface ISPView { Title: string; Id: string; ListId: string; } 2. I have added another private property for tracking selected list Id 3. I have inspected the BaseClientSideWebPart base class and saw a onPropertyChange method. I have added my override implementation of the methood Commented Aug 22, 2016 at 7:18
2

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.

1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.