Webpart list property using PNPJS

Contributor

I am writing a simple web part. It takes a property of "List". The user will pick the list from a dropdown. I am using the tutorial found here:

https://www.sharepointnutsandbolts.com/2016/09/sharepoint-framework-spfx-web-part-properties-dynamic...

 

I have the following function that uses PNPJS to return an array of the lists on the site.

 

  protected fetchLists(): Array<IPropertyPaneDropdownOption> {
    let options: Array<IPropertyPaneDropdownOption> = new Array<IPropertyPaneDropdownOption>();
    sp.web.lists.select('ID', 'Title', 'DefaultViewUrl').get().then(function(data) {
      for (let i = 0; i < data.length; i++) {
        if (data[i].DefaultViewUrl.includes('/Lists/')) {
          options.push({
            key: data[i].Title,
            text: data[i].Title,
          });
        }
      })
      console.log(options);
    });
    return options;
  }

 

The above function is called in the getPropertyPaneConfiguration with the line: 
let lists: Array<IPropertyPaneDropdownOption> = this.fetchLists();

 

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    let lists: Array<IPropertyPaneDropdownOption> = this.fetchLists();
    return {
      pages: [
        {
          header: {
            description: this.description
          },
          groups: [
            {
              groupName: 'Properties',
              groupFields: [
                PropertyPaneDropdown('list', {
                  label: 'List',
                  options: lists
                }),
                PropertyPaneTextField('field', {
                  label: 'Field'
                })
              ]
            }
          ]
        }
      ]
    }  
  }

 

 

The problem is the sp.web.lists... call is seen by the editor as not ways returning a value. I have tried to use the .then(function() {}) to return the array but the IDE still says not all paths return a value. How can I satisfy the IDE and still always get a return array (even if it is empty)?

4 Replies

So I made the following changes. I added the catch method and put another return in there but the IDE still doesn't think that my code always returns as a value.

 

  protected fetchLists(): Array<IPropertyPaneDropdownOption> {
    let options: Array<IPropertyPaneDropdownOption> = new Array<IPropertyPaneDropdownOption>();
    sp.web.lists.select('ID', 'Title', 'DefaultViewUrl').orderBy('Title').get().then(function(data) {
      for (let i = 0; i < data.length; i++) {
        if ((data[i].DefaultViewUrl.includes('/Lists/')) && 
        (
          (data[i].Title != 'SharePointHomeCacheList') || 
          (data[i].Title != 'TaxonomyHiddenList')
        )) {
          options.push({
            key: data[i].Title,
            text: data[i].Title,
          });
        }
      }
      return options;
    }).catch(function(e) {
      return options;
    });
  }

 

I also tried to change the return object of the function to "any", and that will compile but the list doesn't come out in the right format for the getPropertyPaneConfiguration method.
I have concluded that my problem is asynchronous code execution. I have two functions that return a value. function A calls function B and needs to wait for the reply before it continues. This may be more complicated because function B calls another function with a callback. That I can't figure out is how to make function B a callback when I don't control when function A gets called.

This is what I am left with for now. My this.lists object is still empty before it gets to the PropertyPaneDropdown object and I don't know what to do to fix that.

 

  protected fetchOptions(): IPropertyPaneDropdownOption[] {
    var options: Array<IPropertyPaneDropdownOption> = new Array<IPropertyPaneDropdownOption>();
    sp.web.lists.select('ID', 'Title', 'DefaultViewUrl').orderBy('Title').get().then(function(data){
      for (let i = 0; i < data.length; i++) {
        options.push({
          key: data[i].Title,
          text: data[i].Title
        })
      }
      return options;
    });
    return null;
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {

    if (!this.lists) {
      this.lists = this.fetchOptions();
      this.onDispose();
    }

    return {
      pages: [
        {
          header: {
            description: this.description
          },
          groups: [
            {
              groupName: 'Properties',
              groupFields: [
                PropertyPaneDropdown('list', {
                  label: 'List',
                  options: this.lists
                })
              ]
            }
          ]
        }
      ]
    };
  }