When trying to access the key value of a dynamically generated object, it returns as undefined

I am facing a challenge with my student object structure...

{
  Freshmen: [{id: 3}, {id: 5}],
  Sophomores: [{id: 2}, {id: 6}],
  Juniors: [{id: 1}, {id: 8}],
  Seniors: [{id: 9}, {id: 4}, {id: 7}]
}

My goal is to retrieve full student objects from the database based on the ids in the arrays. The desired output should maintain the same object structure.

In my angular component.ts file, I have attempted to achieve this as follows...

  private getStudents(obj) {
    const result = {};
    for (const key of Object.keys(obj)) {
      obj[key].map(item => {
        this.studentsService.geStudentById(item.id).subscribe(res => {
          result[key] = [];
          result[key].push(res);
        });
      });
    }
    return result;
  }

I have injected a service into the component which has a method to fetch student details by id. I call this method within getStudents(). The service returns student objects that I push into the array.

After calling the function, I assign the results to a variable studentDetails like so...

this.studentDetails = this.getStudents(studentObj);

Although everything seems fine, when I try to access

console.log(this.StudentDetails.Freshmen);
, it returns undefined.

I am wondering if there is a more efficient way to handle this situation, such as using arr.reduce() instead of arr.map()? I did try reduce but encountered an issue where only one item was returned. Any advice or suggestions would be highly appreciated.

Answer №1

The issue stems from the fact that the return statement is being executed prematurely, before the async getStudentById() requests have finished processing.

A possible solution would be to utilize RxJS to combine and synchronize the requests, allowing you to work with the data only once all results are available.

By integrating RxJS into your function, the structure could resemble:

private getStudents(obj) {
  const result = {};

  // Array to hold observables
  let observables: Observables<void>[] = [];

  // Create observables for each request
  for (const key of Object.keys(obj)) {
    obj[key].map(item => {
      observables.push(
        this.studentsService.geStudentById(item.id)
          .map(res => {
            result[key] = [];
            result[key].push(res);
        });
      });
    );
  }

  // Combine and wait for all observables to emit a value
  of(...observables)
    .pipe(zipAll())
    .subscribe(() => {
      return result;
    });
}

Additionally, it may be more efficient to retrieve all students at once and filter them locally instead of making individual requests per student (depending on total number of students).

Answer №2

When making an asynchronous call, make sure to wait for all requests to be completed before returning the result. Otherwise, you may end up with an empty object being returned prematurely.

To address this issue, consider refactoring your code as follows:

function getStudents(obj) {
    const result = {};
    const requests = [];
    
    for (const key of Object.keys(obj)) {
        obj[key].forEach(item => {
            let currentRequest = this.studentsService.getStudentById(item.id)
                .subscribe(res => {
                    if (!result[key]) {
                        result[key] = [];
                    }
                    result[key].push(res);
                });
                
            requests.push(currentRequest);
        });
    }
    
    return new Observable(observer => {
        forkJoin(requests).subscribe(() => {
            observer.next(result);
            observer.complete();
        });
    });
}

}

Then assign the studentDetails property like so:

this.getStudents(studentObj).subscribe(result => this.studentDetails = result)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is your Node.js asynchronous parallel function not performing as expected?

I have a series of promises that I need to execute sequentially, but it's getting messy with all the promise returns. To simplify this process, I decided to use the async library and tried out the parallel method. However, instead of running one after ...

Utilize style as a module in Angular

The issue at hand: Let's take a look at this project structure: /src /public /styles /general /tables.scss /secure /components /someTable1 /someTable.component.ts /someTable.component.css /someTa ...

Error: Unable to locate 'v8' in NextJS when using Twin Macro

I am encountering the error message Module not found: Can't resolve 'v8' when using a package in Nextjs with TypeScript. If I use a .js file, everything works fine. However, when I switch to a .tsx file, it throws a Module Not found error. ...

"Learn how to easily format specific characters in JavaScript using the text plugin to create bold text strings with a unique

I would like to transform this text into something like "|| something 1 || something 2 || more || last one ||" and then make all of that string bold by adding "|" around it then it would look like this "|| something 1 || something 2 || more || last one | ...

AngularJS dropdown menu for input selection binding

Hey there, I need some help with the code below: <input type="text" class="form-controlb" ng-model="item.name" id="name" placeholder="Enter Name" /> Also, I have a dropdown as shown here: <div class="col-sm-12" ng-model="query"& ...

Creating a recursive function using NodeJS

This particular challenge I am tackling is quite intricate. My objective is to develop a recursive function in NodeJS that can interact with the database to retrieve results. Based on the retrieved data, the function should then recursively call itself. F ...

Update: Cannot mark as invalid a nested document that has not been included in an array

I recently encountered an issue with my upsert query in mongoose. It was functioning perfectly in version 3.8, but ever since I upgraded to version 4, I've been facing the following error: Unable to invalidate a subdocument that has not been added to ...

Implement Sorting Functionality in Angular Using FormArray

Hello, I am a beginner in Angular and need some help with implementing sorting functionality. I have an input class called Foo which contains a list of books with properties like Id, Title, and Description. These books are displayed in a table where users ...

Preserve the XHR-generated configuration when the browser is refreshed

My PHP page features a navigation menu with options such as Home, About Us, and Profile. When clicking on the "About Us" link from the home page, it loads an Ajax response displaying the information without reloading the page. However, if the user decide ...

"Utilizing jQuery to apply a class based on the attributes of CSS

Is there a way in jQuery (or plain JS) to create a condition based on whether a div has a specific CSS attribute? For instance, I need jQuery to apply position:fixed to an element's CSS when another element has display:none, but switch back to positi ...

Experiencing problems with web page layout when using bootstrap on IE8?

Here is a code snippet that functions correctly in IE9 and later versions, but encounters issues in IE8: <div class="col-lg-5 col-md-5 col-sm-6 col-xs-6" id="div1"> <div class="panel panel-default" style="" id="panel1"> ...

How to activate a window that's been minimized in Chrome

I am experiencing an issue with a button that is supposed to open a new window as a popup below the parent page. It works correctly in IE and Firefox, but in Chrome, the popup appears on top of the parent window. Can someone please provide a solution? Fo ...

Retrieve the current state within a redux action

Many experts recommend consolidating the logic in action creators to streamline the reducer's logic. Picture a basic (normalized) state: const initialState = { parent: { allIds: [0], byId: { 0: { parentProperty: `I'm the ...

Showing a pop-up on a click of a dynamically created table row, showcasing information specific to that row

I am facing a challenge with my dynamically generated table that is based on the JSON response from an AJAX call. What I am trying to achieve is to display additional data in a modal when a table row is clicked. This would be simple if the data was hard co ...

Automatically forward to m.example.com on mobile devices using nodejs

Is there a way to create a subdomain in Node.js, such as m.example.com, and have it redirect to m.example.com on mobile devices? I've searched for answers but haven't found a satisfactory solution. One suggestion is to use nginx in front of Node, ...

Effective RxJS Subscription Management - Minimize Unnecessary Subscriptions

What strategies can I implement to prevent subscribing excessively? Is there a way to automatically unsubscribe any active subscriptions? clickDown(e) { this.mouseMoveSubscription = fromEvent(this.elementRef.nativeElement, 'mousemove') .s ...

What are the best methods for adjusting the size of a game's

I create games using HTML5/CSS/JS, but I am struggling to figure out how to make them scale to different screen resolutions. It seems like a simple task, but I can't seem to grasp it. SOLVED var RATIO = 480 / 800; // Initial ratio. function resize() ...

Exploring different methods to locate a random ID using XPATH, CSS path, and selector while conducting Selenium c# testing on a CMS tool

Issue: Hey there, I'm currently working on testing a CMS tool with selenium in C#. The problem I'm facing is finding a suitable selector for a small drop-down button due to the random generation of IDs for all selectors. Every time the script run ...

Creating a personalized input slider: A step-by-step guide

I have a question about how to design a custom input slider with the label inside the field itself. The desired output should look like the screenshot below: I have successfully created the input field part, but I am struggling with adding the label and ...