0

Once again, asynchronicity is kicking my butt. Problem: I have a configuration file based on which I have to build a multi level object, for example:

export const personnelTasks = {
  manager: {
    administrative: ['meetings', 'evaluation', 'time-reporting', 'vacation-approval'],
    operational: ['budgeting', 'supervising', 'customer-complaints']
  },
  frontDesk: {
    administrative: ['time-tracking', 'file-reports', 'cash-reporting', 'take_on', 'dribble'],
    operational: ['answer-calls', 'face-to-face-meetings', 'cash-counting', 'process-requests']
  }
};

So, depending on whether the employee is a manager or a front desk employee, I will have a report with 2 tabs, administrative and operational and with the various tasks they have to perform. For each of these, the back end returns a series of data, but served from a different API end point. For example, for meetings, I have an API endpoint {DEV_API}/meetings etc.

What I want to do is call all API endpoints at once and build an object for each type of employee, that would look something like this:

const timeTrackingData = {
  administrative: {
    meetings: {...}
    evaluation: {...}
    .....
  },
  operational: {
    budgeting: {...},
    supervising: {...}
    .....
  }
}

My solution is to use the configuration object and build the new object based on it, and for each key, to call the API with an async/ await call.

getTimeTrackingData (employeeID, employeeType) {
    const timeTrackingDataObject = {};
    Object.keys(personnelTasks[employeeType]).forEach((taskCategory) => {
      timeTrackingDataObject[taskCategory] = {};
      personnelTasks[employeeType][taskCategory].forEach(async (task) => {
        timeTrackingDataObject[taskCategory][task] = {};
        timeTrackingDataObject[taskCategory][task] = await axios.get(`${DEV_API}/employees/${employeeId}/time-tracking/${task}`);
      });
    });

    return timeTrackingDataObject;
  },

So when I access the timeTrackingObject, I can see the first level of the Object, but below I see observables that I cannot access. Also, I have serious doubts forEach loop and async/await is the way to go, but I just want to get is solved now and then think of nicer/ more efficient implementations.

Iulia Mihet
  • 650
  • 1
  • 10
  • 34
  • 3
    `getTimeTrackingData` is returned from a **sync** method. However, such method holds **async** operations. I would suggest you to use an approach relying on `Promise.all` and return `timeTrackingDataObject` only once every promise has been resolved. – briosheje May 14 '19 at 18:11
  • Yes, I considered this option, but I need to also build the Object structure. Do you think this needs to be done after the `Promise.all` resolves? – Iulia Mihet May 14 '19 at 18:16
  • No, the code can be kept as it is, there is no need to move the object declaration. Just build a promise array and use `Promise.all`; everything should work as expected. – briosheje May 14 '19 at 18:24

1 Answers1

1

An approach is:

Object.keys(personnelTasks[employeeType]).map(
    taskCategory => personnelTasks[employeeType][taskCategory].map(
        task => axios.get(`${DEV_API}/employees/${employeeId}/time-tracking/${task}`)
    )
)

You have a two-dimensional array with unresolved promises inside. You will have to deal this array with promise.all and THEN build the object.

German Burgardt
  • 375
  • 1
  • 5