Angular:在Typescript中声明对象数组

时间:2019-07-24 07:19:36

标签: angular typescript asynchronous callback

我正在尝试在Typescript中声明一个对象数组。但是,我在检索对象时遇到错误。下面是我的代码。该图显示了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]);
  }
}

我得到的结果在前面包含一个空数组,看起来像这样。

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

当我尝试使用

检索它们时,这将导致未定义
this.info[0]

如果我跳过第二行this.info=[],则会收到一条错误消息,提示

  

无法读取未定义的属性“ 0”

我错误地声明了吗?如何按索引检索信息?

Image shows output of <code>this.attachments</code>

2 个答案:

答案 0 :(得分:0)

问题在于异步调用;

当循环结束并且执行了这两行时...那时reader.onload尚未完成,因此this.info.push(temp);没有运行,当您在控制台中看到空白在下面运行这两行:

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

我们需要做的是让循环结束,并在循环的最后一次迭代(其中i == infos.length - 1中...我们在控制台上打印值并获得正确的结果; >

相关的 TS

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
    }
  }

}

完成working stackblitz here

答案 1 :(得分:0)

Akber Iqbal的答案有效,但是其解决方案不能保证文件与attachments数组的顺序相同,所以

如果有一个重要的解决方案,那就是info项与attachments数组中文件的顺序相同。您正在寻找第一项,因此也许很重要。我们可以使用Promises和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);
      }
    }
  }
}

并通过传递文件和索引并返回临时文件,在此处for循环中处理文件:

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)
  })
}

演示:StackBlitz

相关问题