Working with Arrays of Objects in Typescript with Angular

I am currently trying to define an array of objects in my Typescript code. However, I am encountering issues when accessing these objects. Below is the snippet of my code along with a screenshot showing the output of this.attachments.

info: Info[];

if (this.attachments.length > 0) {
  this.previewInfo(this.attachments);
}

previewInfo(infos) {
  this.info = [];
  for (let i = 0; i < infos.length; i++) {
    let reader = new FileReader();
    reader.onload = (e: any) => {
      var temp = new Info;
      temp = {
        id: i,
        url: e.target.result,
        message: ""
      }
      this.info.push(temp);
    }
    reader.readAsDataURL(infos[i]);
  }
}

The resulting output displays an empty array at the beginning as follows.

[]0: {id: 0, url: "test1", message: ""}
1: {id: 1, url: "test2", message: ""}
2: {id: 2, url: "test3", message: ""}

This leads to undefined errors when attempting to retrieve them using

this.info[0]

If I exclude the second line which resets this.info=[], I encounter an error message that says

Cannot read property '0' of undefined

Is there an issue with how I declared it? How can I effectively access info by its index?

https://i.sstatic.net/H7E1h.png

Answer №1

Akber Iqbal's solution is effective, but there is a concern about maintaining the order of files in the attachments array. In order to address this issue:

Here is an alternative solution that ensures the info items are in the same order as the files in the attachments array. This might be crucial if maintaining file order is important. The implementation involves using Promises and async/await:

async onFileSelected(event) {
  this.attachments = [];
  this.info = [];

  for (let index = 0; index < event.target.files.length; index++) {
    let file = event.target.files[index];
    this.attachments.push(file);
  }

  if (this.attachments.length > 0) {
    for (let i = 0; i < this.attachments.length; i++) {
      try {
        // wait that the file has been processed before moving on to next file
        let temp = await this.readFile(this.attachments[i], i);
        this.info.push(temp)

        if (this.attachments.length === this.info.length) {
          // here we have the first item after all files has been completed
          console.log(this.info[0])
        }
      } catch (err) {
        console.log(err);
      }
    }
  }
}

Additionally, the file processing within the for-loop involves passing the file and its index and returning the temporary file:

readFile(file, i) {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();

    reader.onload = (e: any) => {
      let temp = {
        id: i,
        url: e.target.result,
        message: file.name, // for testing I put the file name as message
      }
      resolve(temp);
    };
    reader.readAsDataURL(file)
  })
}

DEMO: StackBlitz

Answer №2

The issue arises from asynchronous calls in the code;

Once the loop finishes and these 2 lines are executed... at that point, the reader.onload is still ongoing and hence this.info.push(temp); doesn't get executed leading to a blank output in your console when running the following 2 lines:

console.log(this.info);
console.log(this.info[0]); //this is what i need

To resolve this, we should allow the loop to finish and only in the very last iteration (where i == infos.length - 1) of the loop... we display the values on the console to obtain the correct outcome;

relevant TypeScript:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {

  //Variable declaration
  attachments = [];
  info = [];

  onFileSelected(event) {
    this.attachments = [];
    for (var index = 0; index < event.target.files.length; index++) {
      var file = event.target.files[index];
      this.attachments.push(file);
    }
    if (this.attachments.length > 0) {
      this.previewInfo(this.attachments);
      console.log('caller', this.attachments);
    }
  }

  previewInfo(infos) {
    this.info = [];
    if (infos) {
      for (let i = 0; i < infos.length; i++) {
        let reader = new FileReader();
        reader.onload = (e: any) => {
          let temp = {
            id: i,
            url: e.target.result,
            message: "",
          }
          //console.log(temp);
          if (i == infos.length - 1) {
            this.pusher(temp, true);
          } else {
            this.pusher(temp, false);
          }
          //this.info.push(temp, function(){ console.log('pushed'); } );
        }
        reader.readAsDataURL(infos[i]);
      }
      console.log('empty: ', this.info);
      console.log('empty: ', this.info[0]); //this is what i need
    }
  }

  pusher(tempFile, lastFile) {
    this.info.push(tempFile);
    if (lastFile == true) {
      console.log('Correct Filled: ', this.info.length);
      console.log('Correct Filled: ', this.info[0]); //this is what i need
    }
  }

}

view the complete working example on StackBlitz here

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

Dealing with numerous dynamically generated tables while incorporating sorting in Angular: a comprehensive guide

I am faced with a challenge involving multiple dynamically created Angular tables, each containing the same columns but different data. The issue at hand is sorting the columns in each table separately. At present, I have two tables set up. On clicking the ...

What steps should I take to retrieve my information from a typescript callback function?

While I am familiar with using callbacks in JavaScript, I have recently started learning Angular and TypeScript. I am facing an issue with getting my data from a service back to where I need it after executing the callback function. The callback itself i ...

Having trouble with React npm start: 'No chokidar version found' error occurring

After cloning my React-Typescript app on Github Pages and attempting to make some changes, I encountered an issue. Despite running npm install to install all dependencies, when I tried to run npm start, I received the following error message: https://i.st ...

A collection of JSON data containing various diverse values

My classes are not specific and they look like this: type SyncReducerAction<TState> = (state: TState, ...args: any[]) => TState; type AsyncReducerAction<TState, TResult, TRest extends any[]> = { promise: (...args: TRest) => Promise< ...

Unable to execute karma test cases as a result of ngOnDestroy being inaccessible

I have a component structured as follows: export class InkbarComponent implements AfterViewInit, OnDestroy { resizeListener: any; constructor(private _renderer: Renderer, private _elementRef: ElementRef, public renderer: Renderer) { } ngAfter ...

Gain access to TypeScript headers by typing the request (req) object

Is there a way to access headers in a method that is typed with Express.Request? Here's an example code snippet: private _onTokenReceived(req: Express.Request, res: Express.Response): void { const header: string = req.headers.authorizatio ...

What is the best way to compress a file for transfer to a server using gzip?

While attempting to upload a file and send it to the server via a REST API, I am looking for a reliable method to gzip the file. Unfortunately, there is limited documentation available on this topic. Can anyone suggest the most effective approach to achiev ...

Adjusting a variable's value based on the changes of another variable

In the process of developing an application feature for managing favorites, I am integrating data from two different sources. One source is a const file that I am exporting as an observer (observerA$), while the other source is a database containing only t ...

The factory class is responsible for generating objects without specifying their type

I manage a factory that specializes in facilitating dependency injection. Here's an example of what it looks like: import SomeImportantObject from "./SomeImportantObject" import DataInterface from "./DataInterface" class NoodleFactory { this.depen ...

The icon for the ng-bootstrap datepicker calendar is not showing up

I recently implemented a date picker using angular-cli and ng-bootstrap. The datepicker is working perfectly after installing it from npm and adding it to the main module. However, I am facing an issue with the icon not displaying properly. Check out the ...

What causes the function endpoint to become unreachable when a throw is used?

One practical application of the never type in typescript occurs when a function has an endpoint that is never reached. However, I'm unsure why the throw statement specifically results in this unreachable endpoint. function error(message: string): ne ...

Obtain a string of characters from different words

I have been trying to come up with a unique code based on the input provided. Input = "ABC DEF GHI" The generated code would look like, "ADG" (first letter of each word) and if that is taken, then "ABDG" (first two letters o ...

Navigating Errors within Express Class Using Typescript

I encountered an issue while transforming my Express.js application into a Typescript class, specifically with error handling. Below is the content of my App.ts class file: import express from 'express'; import compression from 'compression& ...

How can I send a value to an Angular element web component by clicking a button with JavaScript?

I want to update the value of an input in an Angular component by clicking on a button that is outside of the Angular Element. How can I achieve this in order to display the updated value in the UI? Sample HTML Code: <second-hello test="First Value"&g ...

Leveraging CSS attribute selectors within JSX using TypeScript

With pure HTML/CSS, I can achieve the following: <div color="red"> red </div> <div color="yellow"> yellow </div> div[color="red"] { color: red; } div[color="yellow"] { color: yellow; ...

encountering an issue during the installation of a node package

Encountering this error while trying to install npm i npm ERR! While resolving: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9bfaf5fceef7fae9b6f2f6fafcfeb6fefff2eff4e9dbabb5abb5aa">[email protected]</a> npm ERR! ...

Display JSON element in Angular only once

Below is the code snippet: <ion-content padding> <h1>Datum: </h1> <ion-list> <ion-item *ngFor="let u of tecaj"> <h2>{{u.datum}}</h2> <h2>{{u.drzava}} | {{u.valuta}}</h2> ...

Is there a more efficient solution for incorporating undefined and null into a type apart from developing a custom generic function?

Often in programming, we encounter methods where one or more parameters can be null or undefined (sometimes both with derived types). This can result in long method signatures like this: doThing( user: User | undefined | null, thing: Thing | undefined ...

How can I get video playback in IOS to work with Videogular2 using HLS?

I recently integrated videogular2 into my Angular 6 app to display HLS streams. Everything seems to be working smoothly on desktop and Android devices, but I encountered an error when testing on IOS: TypeError: undefined is not an object (evaluating &apos ...

The parameter type must be a string, but the argument can be a string, an array of strings, a ParsedQs object, or an array of ParsedQs objects

Still learning when it comes to handling errors. I encountered a (Type 'undefined' is not assignable to type 'string') error in my code Update: I added the entire page of code for better understanding of the issue. type AuthClient = C ...