Загрузка изображений вместе с кратким списком пользователей в методе Angular ngOnInit завершается неудачно, изображения всегда неопределены - PullRequest
0 голосов
/ 26 сентября 2019

У меня есть страница, содержащая несколько загрузочных карт (примерно от 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;
        });
    });
}

этот код не может получить изображения с сервера, они всегда отсутствуют (не определено).Как это должно выглядеть, чтобы сделать это правильно?

Ответы [ 3 ]

1 голос
/ 26 сентября 2019

Насколько я понимаю, причина, по которой это происходит, заключается в том, что 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;
  })
});

Таким образом, ваш код будет разрешен только после завершения всех асинхронных вызовов, что не позволит вам получить неопределенные данные.

1 голос
/ 26 сентября 2019

Вы должны поместить this.students.push ({student: std, hasImage: true, image: this.imageToShow}); внутри this.fileService.getImage подписка, поскольку еевыполнение асинхронно.

С другой стороны, вы должны избегать вложенных подписок.Проверьте эту ссылку https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs

Также, если вы используете подписки, вы должны отменить их в методе ngOnDestroy, чтобы избежать утечек памяти.Проверьте эту другую ссылку https://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/

Я надеюсь, что это будет полезно для вас

С уважением

0 голосов
/ 27 сентября 2019

После объединения всех предложений и ответов рабочий код выглядит следующим образом:

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;

}

и теперь все изображения появляются на экране, как и ожидалось

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...