2

Problem with below code is the component is rendered first before completing the rest call, so DOM is empty. The second ajax in loop will trigger 50 times as there are 50 direct reportees under one manager. The second ajax call is to get Display name of the direct reportee, as the first ajax calls gives only emails in the data.d.DirectReports.results. So, how to make all the ajax calls to complete first and then render the component to display data in DOM ?

public componentDidMount(){
    this.getReportees();
}
getReportees = () => {
    var reportees = [];
    var reactHandler = this;
    var drReportess = [];
    $.ajax({
      url: this.siteUrl+"/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=@v)?@v='" + encodeURIComponent(accountName) + "'&$select=DirectReports",
      method: "GET",
      headers: { "Accept": "application/json; odata=verbose" }
    }).done((data)=>{
      let length: Number = data.d.DirectReports.results.length > 0 ? data.d.DirectReports.results.length : 0;
      if(length>0){
        $.each(data.d.DirectReports.results, function (i, value: string) {
          reportees.push(value);
        });
        $.each(reportees,function(i,value){
          $.ajax({
            url:  this.siteUrl+"/_api/SP.UserProfiles.PeopleManager/GetUserProfilePropertyFor(accountName=@v,propertyName='PreferredName')?@v='" + encodeURIComponent(value) + "'",
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" }
          }).done((data)=>{
            drReportess.push({
              DisplayName: data.d.GetUserProfilePropertyFor,
              LoginName: value
            })
          })
        })
        reactHandler.setState({
          directReportees: drReportess
        })
        console.log(reactHandler.state.directReportees);
      } 
    })
  }
public render(): React.ReactElement<IDashboardProps> {
   console.log('Render');
   return(
   <table className="ms-Table course-table">
      <thead>
         <tr>
            <th>Team Members</th>
         </tr>
      </thead>
      <tbody>
      {this.state.directReportees && this.state.directReportees.map((item, i) => {
       return [
          <tr>
              <td>{item.DisplayName}</td>
           </tr>
        ]
       })}
       </tbody>
   </table>
);
}

Here comes Render first (console.log) and then data is loading later, so table is empty.

Srik A
  • 63
  • 1
  • 5
  • Why not just clear the state's `directReportees` array before looping, and have the Ajax call append each reportee object to the state (via `setState()`) as it completes? That way it won't matter if the results come in asynchronously. – kmoser Jun 01 '20 at 03:25
  • @kmoser: you mean to say to push setState() in done function inside loop ? i already tried that, it is not helping. – Srik A Jun 01 '20 at 04:45
  • Not helping meaning it doesn't work? Or gives an error? – kmoser Jun 01 '20 at 04:58
  • Sorry i mean, even after placing setstate() inside done function the result is same, dom is empty and ajax is completing after dom loads. ``` public render(): React.ReactElement { console.log("render"); return(
    )} ``` . here render in console log comes first and then this.state.directReportees comes later.
    – Srik A Jun 01 '20 at 05:45

1 Answers1

0

Call your this.getReportees() funtion from onInit which run before render

public onInit(): Promise<void> {
  await this.getReportees();
}

hope this will solve your issue.

Milind
  • 1,855
  • 5
  • 30
  • 71