Unable to loop through array generated by service - potential async complication?

In my service, I am populating an array of items by calling a function like this:

items: IItem[] = [];
...
LoadItems() {
        this.GetItems().subscribe((res) => {
            // console.log(res);
            if (res.status == 200 && res.body.data != undefined) {
                var data = res.body.data;
                this.items.push({
                        Id: data[i].id,
                        IsBlue: data[i].isBlue, //this is a bool
                    });
                }    
            }
            // console.log(this.items.length);
        });
    }

This function is called within the ngOnInIt method in my app.component.ts file. Afterwards, I want to filter out and work with only the blue items in the array in item.component.ts like so:

GetBlueItems(items: IItem[]) {
    var blueitems: IItem[] = [];
    console.log(items); //this returns the array correctly

    for (let i = 0; i < items.length; i++) {
        if (items[i].isBlue) {
            blueitems.push(items[i]);  
        }
    }

However, the loop is not iterating through the array. When I check the length of the array using console.log(items.length), it returns 0, even though console.log(items) shows that the array is not empty.

I have attempted to use a forEach loop as well, but it also fails to iterate through the array:

items.forEach(item => {
    if (item.isBlue) {
        blueitems.push(item);  
    }
});

I would like to be able to access and use this array outside of the subscription block. I do not need the array to be continuously updated. The array is needed for displaying information in the HTML, as well as various functions within the application such as managing a shopping cart and checkout process.

Edit: I want to utilize the array outside the subscription block for the purpose of displaying information in HTML, as well as using it for tasks like adding items to a shopping cart and completing transactions. It seems challenging to effectively utilize the array if I am restricted to using it only within the subscription block.

Answer №1

To tackle this issue, I suggest leveraging RxJS Streams instead of subscribing inside a service. Simply pass the Observable and let components utilize either the async pipe or signals to transfer data to templates.

interface IItem {
  IsBlue: boolean;
  Id: number;
}

const fakeResponseData: IItem[] = [
  {
    Id: -1,
    IsBlue: true
  },
  {
    Id: 0,
    IsBlue: false
  }
]

const fakeResponse: HttpResponse<IItem[]> = new HttpResponse({
  body: fakeResponseData,
  status: 200,
})

const fakeRequqest = of(fakeResponse);

@Injectable()
export class MyService {

  private item$: Observable<IItem[]>;

  LoadItems(): Observable<IItem[]> {
    if (!this.item$) {
      this.item$ = fakeRequqest.pipe(
        map(response => response.body),
        filter((response): response is IItem[] => response !== null && response !== undefined),
        shareReplay() // shareReplay is optional, it depends on your use case, now we have a little cache
      );
    }
    return this.item$
  }
}

@Component({
  selector: 'myComponent',
  template: `<ul><li *ngFor="let item of items$ | async">{{item.IsBlue}}</li></ul>`,
  standalone: true,
  imports: [AsyncPipe]
}) 
export class myComponent{

  private readonly myService = inject(MyService);

  protected readonly items$ = this.myService.LoadItems().pipe(
    map(items=> items.filter(item => item.IsBlue))
  )

  /** example angular 17+ with signals 
    protected readonly blueItems = toSignal(
      this.myService.LoadItems().pipe(map(items=> items.filter(item => item.IsBlue)))
    );

    // in template
    @for (item of blueItems(); track item.id) {
      {{item.IsBlue}}
    }
  */
}

Answer №2

It seems like the initial code block lacks the forEach loop required for loading the data properly.

    items: IItem[] = [];
    blueitems: IItem[] = [];
    ...
    LoadItems() {
        this.GetItems().subscribe((res) => {
            // console.log(res);
            if (res.status == 200 && res.body.data != undefined) {
                var data = res.body.data;
                data.forEach((item: any, i: number) => {
                    this.items.push({
                        Id: item[i].id,
                        IsBlue: item[i].isBlue, //this is a bool
                    });
                });
                }    
            }
            // console.log(this.items.length);
            this.getBlueItems(this.items);
        });
    }

Make sure to invoke this function with the help of a forEach loop.

GetBlueItems(items: IItem[]) {
    console.log(items); //this returns the array correctly

    items.forEach(item => {
        if (item.isBlue) {
            this.blueitems.push(item);  
        }
    });
}

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

Transform the function into an observable form

Is there a way to transform this function into an observable? I need it to check for the existence of a document based on a query, and I want to be able to subscribe to it in order to create a new document if one does not already exist. Unfortunately, I a ...

Transferring functionality from a child component to a parent component

I have a Base Component called ListComponent and a ParentComponent named Businesses2ListComponent. The concept is to have multiple types of Lists with tables that all stem from the ListComponent. This requires passing the correct service accordingly. In t ...

Retrieve every hour between two specific timestamps

I am attempting to retrieve all dates between two timestamps that fall on a specific day of the week. I have a start date represented by 'start1' and an end date represented by 'end1'. Additionally, I have a list of days with correspon ...

The juvenile entity does not align with the foundational entity [typescript]

After setting "strict": true in my tsconfig.json, I encountered compiler errors when attempting to run the code. To replicate and explore this issue further, you can try running the following code snippet. The problem arises when the child clas ...

Tips for sending props, state, or arguments to a TypeScript React component

Hey there, total newbie here... I'm currently working on a school project and I've hit a bit of a roadblock... I'm attempting to pass some props from one component to another, but for some reason, it's not working properly. The goal ...

Substitute the specific class title with the present class

Here is a sample class (supposed to be immutable): class A { normalMethod1(): A{ const instance = this.staticMethod1(); return instance; } static staticMethod1: A(){ return new this(); } } The code above works fine, but how can I re ...

The production build encountered an issue as it was anticipating 3 arguments, however, it only received

import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'elipsis' }) export class ElipsisPipe implements PipeTransform { transform(text, length, clamp) { text = text || ''; clamp = clamp || '...& ...

Declaring types globally in Visual Studio Code for JavaScript programming

My /typings/$app.d.ts file has the following structure: declare class App { test: object } export const $app: App; https://i.sstatic.net/3HW7M.png In order to enable intellisense, I have to auto-import it, resulting in a line like this at the begin ...

Retrieving information from a JSON reply within an Angular 2 service

I am currently utilizing a service in angular 2 that retrieves JSON data from an API (). The code for fetching the data is depicted below: getImages() { return this.http.get(`${this.Url}`) .toPromise() .then(response => response.json() ...

After extraction from local storage, the type assertion is failing to work properly

I have a unique situation in my Angular project where I have stored an array of data points in the local storage. To handle this data, I have created a custom class as follows: export class Datapoint { id: number; name: string; // ... additional pr ...

Tips for inserting a string into an array nested within an object stored in a state array

Currently, the variable sizeVariant is a string array and I am trying to append strings to it using an onClick event. The function findIndex seems to be working fine. However, there seems to be an issue with the concatenation section. It appears that using ...

Session is not functioning properly as anticipated

import * as express from 'express'; import * as session from 'express-session'; import * as bodyParser from 'body-parser'; const app: express.Express = express(); app.use(bodyParser.json()); app.use(session({ secret: &apos ...

Downloading Files in Angular Using HttpClient - Extracting File Names from the Server Response

I am currently working on retrieving a File from an API URL. My goal is to display this uploaded file in an input field along with its name. To achieve this, I have implemented the following service function: getDocument(): Observable<Blob> { c ...

Issue encountered during the construction of the Angular project in production

$ ng build --prod Date: 2018-12-06T18:43:56.689Z Hash: e36e17503416de0fc128 Time: 7480ms chunk {0} runtime.ec2944dd8b20ec099bf3.js (runtime) 1.44 kB [entry] [rendered] chunk {1} main.9868d9b237c3a48c54da.js (main) 128 bytes [initial] [rendered] chunk {2} ...

The attribute specified is not present on the element within the array

I'm attempting to create an array that includes an object with initialized properties and a number. Yet, I encounter this error message: The error states: 'Property 'foo' does not exist on type 'number | IObj'. The proper ...

Trouble with executing simple code in a new project (binding, input, ng model) across different browsers

I am encountering an issue with this code snippet. It's a simple one - I want to display the input text in my view, but nothing is showing up. The code runs fine in an online simulator, but when I try it in my browser, it doesn't work at all. I&a ...

Enriching SpriteWithDynamicBody with Phaser3 and Typescript

Is there a way to create a custom class hero that extends from SpriteWithDynamicBody? I'm unable to do so because SpriteWithDynamicBody is only defined as a type, and we can't extend from a type in Typescript. I can only extend from Sprite, but ...

Encountering Error: Unable to create new component as PriorityQueue is not recognized as a constructor

While trying to create a new component using Angular CLI with the command ng g c navbar, I encountered an unusual error message: core_1.PriorityQueue is not a constructor TypeError: core_1.PriorityQueue is not a constructor at new TaskScheduler (/h ...

What is the procedure for cancelling a file upload in the FileUpload component of PrimeNG?

1. Issue Overview Looking to terminate file upload in PrimeNG's FileUpload component when certain filename patterns are detected. Using Angular 6.0.7 and PrimeNG 6.0.2. 2. Initial Strategy 2.1. HTML Code <p-fileUpload #fileUploader name="file" ...

Formatting Time in Angular 2 Using Typescript

Upon reviewing my date source, I found the following: TimeR ="2017-02-17 19:50:11 UTC"; Within the HTML file, I implemented this code snippet <span class="text-lg">{{TimeR | date: 'hh:mm'}}</span> The current output displays the t ...