#javascript #html #angular #frontend
#javascript #HTML #угловой #интерфейс
Вопрос:
У меня есть компонент uploader, который работает как dropzone для файлов. Когда я отбрасываю файлы туда, они собираются files: File[]
. Я хочу отобразить их с помощью ngFor, чтобы пользователь знал, что загружается. Проблема в том, что когда я загружаю файл, буфер преобразует его в urls: []
. Я проверил это в отладчике, и значения URL-адресов действительно были там. Но * ngFor не отображает их, пока я не наведу курсор на следующее изображение в dropzone (просто наведите курсор, без удаления). Сценарий выглядит так: я загружаю изображение, и ngFor не отображает изображения. Я навожу второе изображение на dropzone, и отображается первое изображение. Я отбрасываю второе изображение, а затем все еще отображается первое изображение. Затем я навожу другой и показываю второй.
Это мой код компонента:
import { Component, OnInit, Input, OnDestroy, Output, EventEmitter } from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import { StorageService } from 'src/app/core/services/storage.service';
import { AngularFireUploadTask } from '@angular/fire/storage';
import { ProductService } from 'src/app/core/services/product.service';
@Component({
selector: 'app-uploader',
templateUrl: './uploader.component.html',
styleUrls: ['./uploader.component.scss']
})
export class UploaderComponent implements OnInit, OnDestroy {
eventSubscriptions: Subscription[] = [];
@Input() productIdEvent: Observable<void>;
@Input() resetEvent: Observable<void>;
@Output() onChange = new EventEmitter<number>();
isHovering: boolean;
files: File[] = [];
urls = [];
task: AngularFireUploadTask;
constructor(private storageService: StorageService, private productService: ProductService) { }
toggleHover(event: boolean) {
this.isHovering = event;
}
onDrop(files: FileList) {
for (let i = 0; i < files.length; i ) {
this.files.push(files.item(i));
var reader = new FileReader();
reader.readAsDataURL(files.item(i)); // read file as data url
reader.onload = (event) => { // called once readAsDataURL is completed=
this.urls.push(reader.result);
}
}
}
uploadFiles(productId){
let id = 0;
for(let file of this.files){
this.storageService.uploadFile(file,productId "/" ( id))
let reader = new FileReader();
}
}
ngOnInit(): void {
this.eventSubscriptions.push(this.productIdEvent.subscribe(val => this.uploadFiles(val)));
this.eventSubscriptions.push(this.resetEvent.subscribe(() => this.files = []));
}
ngOnDestroy(): void {
this.eventSubscriptions.forEach(subscription => subscription.unsubscribe());
}
}
И html
<div class="dropzone" dropzone (hovered)="toggleHover($event)" (dropped)="onDrop($event)" [class.hovering]="isHovering">
<h3>Strefa zrzutu</h3>
</div>
<div><img *ngFor="let url of urls" [src]="url"></div>
<div>{{files.length}} zdjęcia</div>
директива
import { Directive, Output, EventEmitter, HostListener } from '@angular/core';
@Directive({
selector: '[dropzone]'
})
export class DropzoneDirective {
@Output() dropped = new EventEmitter<FileList>();
@Output() hovered = new EventEmitter<boolean>();
@HostListener('drop', ['$event'])
onDrop($event) {
$event.preventDefault();
this.dropped.emit($event.dataTransfer.files);
this.hovered.emit(false);
}
@HostListener('dragover', ['$event'])
onDragOver($event) {
$event.preventDefault();
this.hovered.emit(true);
}
@HostListener('dragleave', ['$event'])
onDragLeave($event) {
$event.preventDefault();
this.hovered.emit(false);
}
}
Комментарии:
1. похоже на ошибку с вашим обнаружением изменений. возможно, вызвано
dropzone
директивой или какой-либо другой библиотекой, предоставляющей это. вероятно, это связано сngZone
соображениями производительности и не осознает последствий этого.2. @bryan60 обновлено
3. хм .. выглядит нормально. используете ли вы
OnPush
обнаружение изменений где-то выше в вашем дереве компонентов? Если нет, вы можете захотеть воссоздать это в stackblitz (без базы данных для хранения / загрузки / запуска)4. да, dropzone является частью формы. Я удалил OnPush из родительского компонента, но это не помогло
5. для меня все это выглядит достаточно хорошо, если вы не создаете onpush-часть дерева. не ясно, что вы пытаетесь сделать внутри своей
uploadFiles
функции, где вы создаете экземплярFileReader
, а затем ничего с ним не делаете, но idk, что вы ожидаете, что там произойдет. я бы попытался воссоздать это в stack blitz.