Ваша проблема
У вас есть форма, которая позволяет пользователям загружать изображение или указывать URL-адрес изображения.
Когда форма отправлена, вы отображаете загруженное изображение.
Функции, возвращающие URL-адрес изображения, запускаются несколько раз или не работают.
Мой диагноз
Есть несколько проблем с вашим текущим решением.
- Многократное выполнение функции
Вы связываете <img src />
с функцией, которая разрешает URL. Каждый раз, когда обнаруживается изменение, ваша функция будет запрашиваться. Вы должны выполнять как можно меньше обработки в цикле обнаружения изменений.
Обычно это можно исправить, установив для компонента changeDetectionStrategy
значение OnPush
, добавив ChangeDetectorRef
и вручную вызвав detectChanges()
когда вы хотите активировать обнаружение изменений. Тем не менее, я думаю, что в этом случае это будет покрывать трещины, так что это не мое предлагаемое решение.
Невозможно разрешить URL для загруженного файла
Вы пытаетесь привязать <img src />
к функции, которая получает URL данных через FileReader
. Считыватель файлов выполняется асинхронно, поэтому вам нужно будет обернуть это в какое-то обещание / наблюдаемое и использовать для вызова этот канал async
.
НО вам не следует делать это по причине, указанной в пункт 1.
Мой подход
Я собираюсь сосредоточиться на конкретной c проблеме разрешения URL-адреса изображения, поскольку у вас есть сложная форма, которая в основном выходит за рамки для этой проблемы.
Мой главный рефакторинг - вывести разрешение URL из цикла обнаружения изменений. Сначала я разрешу URL, а затем добавлю элемент в массив с разрешенным URL.
Моя реализация
Я собираюсь абстрагировать вашу проблему в простое приложение, в которое вы можете загрузить изображение и / или указать URL изображения. Разрешенные изображения будут отображаться после отправки формы.
Компонент довольно тривиален, поэтому я покажу службу только здесь:
image.service.ts
export class ImageService {
private images$ = new BehaviorSubject<{ url: string, type: string }[]>([]);
private images: { url: string, type: string }[] = [];
addFromFile(file: File) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = event => {
this.addImage({
url: reader.result.toString(),
type: 'fromFile'
});
};
}
addFromUrl(url: string) {
this.addImage({
url: url,
type: 'fromUrl'
});
}
getImages(): Observable<{ url: string, type: string }[]> {
return this.images$.asObservable();
}
private addImage(image: { url: string, type: string }) {
this.images.push(image);
this.images$.next(this.images);
}
}
Обратите внимание, что изображения помещаются в массив и тему только после разрешения URL.
Я определенно упростил это по сравнению с вашей формой, но я думаю, что вы могли бы черпать вдохновение из этот подход, чтобы исправить вашу проблему.
DEMO: https://stackblitz.com/edit/angular-yhnnwv