0

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`;
        }
      }
  }
  • 1
    You have to manage promises, can you share your code with async/await? – RiccardoGDev Apr 1 at 8:45
  • Sure, I edited it into my question. – T. Friedrichsen Apr 1 at 10:35
1

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);
      }
  • The second snippet helped a bit. Now my code waits for await this._getLinks(); But not for this._getUserInformation() - which is executed at last. :/ – T. Friedrichsen Apr 1 at 11:36
  • I've updated the second method to wait even the foreach execution, can you try? – RiccardoGDev Apr 1 at 12:16
  • 1
    It works! Wow! Thank you so much. I really gotta learn how to keep my promises. Thank you so much! :) – T. Friedrichsen Apr 1 at 12:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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