简体   繁体   English

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

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

I have a page containing few bootstrap cards (roughly 2 to 5).我有一个页面包含一些引导卡(大约 2 到 5 张)。 They present student info.他们提供学生信息。 I also want to load images of these students (from the server) together with their details but I can't figure out how.我还想(从服务器)加载这些学生的图像及其详细信息,但我不知道如何。 Here is what I got:这是我得到的:

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 code fails to get the images from the server, they are always missing (undefined).此代码无法从服务器获取图像,它们总是丢失(未定义)。 How it should look like to make it right?它应该是什么样子才能使它正确?

You must put this.students.push({student: std, hasImage: true, image: this.imageToShow});你必须把this.students.push({student: std, hasImage: true, image: this.imageToShow}); inside this.fileService.getImage subscription because its execution is async.this.fileService.getImage订阅中,因为它的执行是异步的。

On the other hand you must avoid subscriptions nested.另一方面,您必须避免订阅嵌套。 Check this link https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs检查此链接https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs

Also if you use subscriptions you must unsubscribe them in ngOnDestroy method to avoid memory leaks.此外,如果您使用订阅,则必须在 ngOnDestroy 方法中取消订阅,以避免 memory 泄漏。 Check this other link https://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/检查此其他链接https://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/

I hope that it will be useful to you我希望它对你有用

Regards问候

From my understanding, the reason why this is happening is because forEach is synchronous in nature, but this particular line is asynchronous:据我了解,发生这种情况的原因是因为 forEach 本质上是同步的,但这条特定的行是异步的:

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

Instead you can Promises like this:相反,您可以像这样承诺:

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

This way, your code will be resolved only when all the async calls are completed, preventing you to get undefined data.这样,只有在完成所有异步调用后,您的代码才会被解析,从而防止您获取未定义的数据。

After combining all the suggestions and answers together the working code look like this:将所有建议和答案组合在一起后,工作代码如下所示:

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

also except anonymous type I declared StudentCard used to exchange data:除了匿名类型,我声明 StudentCard 用于交换数据:

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

} }

and now all images appear on the screen as expected现在所有图像都按预期出现在屏幕上

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

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