繁体   English   中英

在 Angular ngOnInit 方法中加载图像和用户的短列表失败,图像始终未定义

[英]Loading images together with short list of users in Angular ngOnInit method fails, images are always undefined

我有一个页面包含一些引导卡(大约 2 到 5 张)。 他们提供学生信息。 我还想(从服务器)加载这些学生的图像及其详细信息,但我不知道如何。 这是我得到的:

students: { student: Student, hasImage: boolean, image: any }[] = [];
loadingData: boolean;
imageToShow: any;

constructor(private userService: UsersService, private fileService: FilesService) {
}

createImageFromBlob(image: Blob) {
    const reader = new FileReader();
    reader.addEventListener('load', () => {
        this.imageToShow = reader.result;
    }, false);
    if (image) {
        reader.readAsDataURL(image);
    }
}

ngOnInit() {
    this.userService.getStudentsOfLoggedUser().subscribe(res => {
        this.loadingData = true;
        res.forEach(std => {
            if (std.imageUrl == null) {
                this.students.push({student: std, hasImage: false, image: undefined});
            } else {
                this.fileService.getImage(std.imageUrl).subscribe(data => {
                    this.createImageFromBlob(data);
                });
                this.students.push({student: std, hasImage: true, image: this.imageToShow});
            }
            this.loadingData = false;
        });
    });
}

此代码无法从服务器获取图像,它们总是丢失(未定义)。 它应该是什么样子才能使它正确?

你必须把this.students.push({student: std, hasImage: true, image: this.imageToShow}); this.fileService.getImage订阅中,因为它的执行是异步的。

另一方面,您必须避免订阅嵌套。 检查此链接https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs

此外,如果您使用订阅,则必须在 ngOnDestroy 方法中取消订阅,以避免 memory 泄漏。 检查此其他链接https://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/

我希望它对你有用

问候

据我了解,发生这种情况的原因是因为 forEach 本质上是同步的,但这条特定的行是异步的:

this.fileService.getImage(std.imageUrl).subscribe(data => {
                    this.createImageFromBlob(data);
});

相反,您可以像这样承诺:

  this.userService.getStudentsOfLoggedUser().subscribe(res => {
  this.loadingData = true;
  let count = 0;
  new Promise((resolve, reject) => {
    res.forEach(std => {
      count++;
      if (std.imageUrl == null) {
        this.students.push({ student: std, hasImage: false, image: undefined });
      } else {
        this.fileService.getImage(std.imageUrl).subscribe(data => {
          this.createImageFromBlob(data);
        });
        this.students.push({ student: std, hasImage: true, image: this.imageToShow });
      }
      if (count > res.length -1) {
        resolve(); //Resolve condition
      }
    });
  }).then(() => {
    this.loadingData = false;
  })
});

这样,只有在完成所有异步调用后,您的代码才会被解析,从而防止您获取未定义的数据。

将所有建议和答案组合在一起后,工作代码如下所示:

createImageFromBlob(studentCard: StudentCard, image: Blob) {
    const reader = new FileReader();
    reader.addEventListener('load', () => {
        studentCard.image = reader.result
    }, false);
    if (image) {
        reader.readAsDataURL(image);
    }
}

ngOnInit() {
    this.userService.getStudentsOfLoggedUser().subscribe(res => {
        this.loadingData = true;
        res.forEach(std => {
            const studentCard = new StudentCard();
            studentCard.student = std;
            if (!std.imageUrl || std.imageUrl == null) {
                studentCard.hasImage = false;
            } else {
                studentCard.hasImage = true;
            }
            this.students.push(studentCard);
        });
        let count = 0;
        this.students.forEach(std => {
            if (std.hasImage) {
                count++;
                new Promise((resolve, reject) => {
                    this.fileService.getImage(std.student.imageUrl).subscribe(data => {
                        this.createImageFromBlob(std, data);
                        console.log(std);
                    });
                    if (count > this.students.length - 1) {
                        resolve(); //Resolve condition
                    }
                }).then(() => {
                    // there is nothing to do here 
                });
            }
        });
        this.loadingData = false;
    });
}

除了匿名类型,我声明 StudentCard 用于交换数据:

export class StudentCard {
student: Student;
hasImage: boolean;
image: any;

}

现在所有图像都按预期出现在屏幕上

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM