Question

I am currently developing a SPFx Extension (Application Customizer). I am relatively new to TypeScript (C# developer) and I can't find my error.

I have the following onInit method:

@override
  public onInit(): Promise<void> {
    this._getUserInformation(); // gets user information via the graph api
    this._getLinks(); // gets information of a SharePoint List
    this._renderPlaceHolders(); // renders my header with information taken from the information I took at the last two methods
  }

But _renderPlaceHolders() gets called before the other two methods. All the time. Why? I tried async/await and Promises, but it didn't work either, rendering always happened before my other two methods. I am sure I made a stupid mistake, but I really can't find it.

Any ideas? :/

Edit with my async/await stuff:

  @override
  public async onInit(): Promise<void> {
    await this._getUserInformation();
    await this._getLinks();
    this._renderPlaceHolders();
  }

  private _getUserInformation() : Promise<any>
  {
    this.context.msGraphClientFactory
      .getClient()
      .then((client: MSGraphClient): void => {
        client
          .api('/me')
          .select("some information")
          .get((error, response: MicrosoftGraph.User, rawResponse?: any) => {
              // do stuff
        });
      });

      return Promise.resolve<any>();
  }

   private _getLinks() : Promise<any> {
      let requestUrl = "url to sharepoint list";

      this.context.spHttpClient.get(requestUrl, SPHttpClient.configurations.v1)  
      .then((response: SPHttpClientResponse) => {  
        if (response.ok) {  
            response.json().then((responseJSON) => {  
              if (responseJSON!=null && responseJSON.value!=null) {  
                let items:any[] = responseJSON.value;

                items.forEach(element => {
                  // do stuff
                });
            }
          });
        }
      });

    return Promise.resolve<any>();
  }

  private _renderPlaceHolders() : void {
      console.log("SmartpointPersonalizedRedirectApplicationCustomizer._renderPlaceHolders()");
      console.log(
        "Available placeholders: ",
        this.context.placeholderProvider.placeholderNames
          .map(name => PlaceholderName[name])
          .join(", ")
      );

      // Handling the top placeholder
      if (!this._topPlaceholder) {
        this._topPlaceholder = this.context.placeholderProvider.tryCreateContent(
          PlaceholderName.Top,
          { onDispose: this._onDispose }
        );

        // The extension should not assume that the expected placeholder is available.
        if (!this._topPlaceholder) {
          console.error("The expected placeholder (Top) was not found.");
          return;
        }

        if (this._topPlaceholder.domElement) {
          this._topPlaceholder.domElement.innerHTML = `
          some html`;
        }
      }
  }
Was it helpful?

Solution

You are resolving the promises without waiting the completation of the asyncronous calls inside methods and without returning anything.

Can you try this code?

  private _getUserInformation() : Promise<any>
  {
    return this.context.msGraphClientFactory
      .getClient()
      .then((client: MSGraphClient): void => {
        client
          .api('/me')
          .select("some information")
          .get((error, response: MicrosoftGraph.User, rawResponse?: any) => {
              // do stuff
        });
      });
  }

   private _getLinks() : Promise<any> {
      let requestUrl = "url to sharepoint list";

      return this.context.spHttpClient.get(requestUrl, SPHttpClient.configurations.v1)  
      .then((response: SPHttpClientResponse) => {  
        if (response.ok) {  
            return response.json().then((responseJSON) => {  
              if (responseJSON!=null && responseJSON.value!=null) {  
                let items:any[] = responseJSON.value;

                return items.forEach(element => {
                  // do stuff
                });
            }
          });
        }
      });
  }

It should be the same of:

private _getUserInformation() : Promise<any>
      {
        const res = this.context.msGraphClientFactory
          .getClient()
          .then((client: MSGraphClient): void => {
            client
              .api('/me')
              .select("some information")
              .get((error, response: MicrosoftGraph.User, rawResponse?: any) => {
                  // do stuff
            });
          });

         return Promise.resolve<any>(res);
      }

       private _getLinks() : Promise<any> {
          let requestUrl = "url to sharepoint list";

          const res = this.context.spHttpClient.get(requestUrl, SPHttpClient.configurations.v1)  
          .then((response: SPHttpClientResponse) => {  
            if (response.ok) {  
                return response.json().then((responseJSON) => {  
                  if (responseJSON!=null && responseJSON.value!=null) {  
                    let items:any[] = responseJSON.value;

                    return items.forEach(element => {
                      // do stuff
                    });
                }
              });
            }
          });
         return Promise.resolve<any>(res);
      }
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top