Domanda

I'm in the process of getting my feet wet with SPFx Application Customizers and have a question regarding the use of promises in TS.

Before my onRender() method is called inside of onInit(), I need to call two functions using PnP JS:

  • The first retrieves the web title
  • The second fetches some user-profile metadata

How can I ensure these two functions complete before the onRender() logic is executed?

    public onInit(): Promise<void> {
        Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);

        pnp.sp.web.select("Title").get().then(w => {
          this._webTitle = w.Title;
        });

        pnp.sp.profiles.myProperties.get().then(function (result) {
          var userProperties = result.UserProfileProperties;
          console.log(userProperties);
          userProperties.forEach(function (property) {
            if (property.Key == "PreferredName") {
              this._userDisplayName = property.Value;
              console.log('user display name: ' + this._userDisplayName);
            }
          });
        }).catch(function (error) {
          console.log("Error: " + error);
        });
    return Promise.resolve<void>();
  }

Currently, I have a race-condition issue where my application customizer is rendered before getting a response in my onInit() functions.

È stato utile?

Soluzione

Batching the 2 requests as suggested by Venkat Konjeti is a great idea, but the question of how to delay your render until these are finished is demonstrated in the jquery-application-toastr sample (full disclosure, this is my sample).

Specifically in the SpfxToastrApplicationCustomizer.ts file. In the webpart class there is a private promise property. This is set in the onInit function when the call to go retrieve the data is made. However, there is no handler (then) at the time.

Later, in the onRender method once things are ready, the then is finally applied and handled. This solves the race condition. Promises will allow you to apply the then function before or after they are resolved. If they haven't resolved then your then won't be called until it is, if the promise already completed, your then will simply receive the results when you're ready for them.

Here's an example (borrowing the batch function from Venkat Konjeti's answer):

private myPromise: Promise<any>;

public onInit(): Promise<void> {
    this.myPromise = this.getData()
}

public onRender(): void {
    this.myPromise.then((results: any) => {
        //Do some rendering stuff
    });
}

function getData() {
    let batch = $pnp.sp.createBatch();

    $pnp.sp.web.select("Title").inBatch(batch).get().then(w => {
        console.log(w.Title);
    });

    $pnp.sp.profiles.myProperties.inBatch(batch).get().then(result => {
        var userProperties = result.UserProfileProperties;
        console.log(userProperties);
        userProperties.forEach(function (property) {
            if (property.Key == "PreferredName") {
              this._userDisplayName = property.Value;
              console.log('user display name: ' + this._userDisplayName);
            }
        });
    });

    return batch.execute();
}

Altri suggerimenti

I think you can use the batch function. Here is example JavaScript code converted to the pnp batch executions.

function rednderBody() {

    var promise = getMyWebDetails();
    promise.then(() => console.log("All done!"));

}

function getMyWebDetails() {
    var batch = $pnp.sp.createBatch();

    $pnp.sp.web.select("Title").inBatch(batch).get().then(w => {
        console.log(w.Title);
    });

    $pnp.sp.profiles.myProperties.inBatch(batch).get().then(result => {
        var userProperties = result.UserProfileProperties;
        console.log(userProperties);
        userProperties.forEach(function (property) {
            if (property.Key == "PreferredName") {
              this._userDisplayName = property.Value;
              console.log('user display name: ' + this._userDisplayName);
            }
        });
    });

    return batch.execute();
}

rednderBody();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a sharepoint.stackexchange
scroll top