angular - UI 上未更新的可观察值
问题描述
我正在开发一个 Angular 应用程序和其他功能,现在我正在开发一个图片库(轮播)。
当用户打开图片库时,他还可以上传新照片。
因为我需要了解全局的上传过程,所以我正在尝试为此实现一个服务,如下所示:
在ts组件中,我具有以下功能:
onUploadFile(files: File[]) {
if (!files?.length) {
return;
}
const uploading = this.attachmentsService
.uploadMultiple(files)
.map((x) => ({ attachment: x }));
uploading.forEach((file) => {
this.filesStateService
.getProgress(file.attachment.url)
.pipe(untilDestroyed(this))
.subscribe({
complete: () => {
this.referenceAttachments = [...this.referenceAttachments];
},
error: () => {
this.deleteAttachment(file);
},
});
});
this.referenceAttachments = [...uploading, ...this.referenceAttachments];
}
附件.service.ts:
uploadMultiple(files: File[]) {
if (!files?.length) {
return [];
}
return files.map((x) => this.upload(x));
}
upload(file: File) {
const fileUpload = this.filesService.upload(file);
this.filesStateService.addProgress(fileUpload.url, fileUpload.progress$);
const attachment: Attachment = {
url: fileUpload.url,
size: file.size,
type: file.type,
};
return attachment;
}
文件.service.ts:
upload(file: File) {
...
return {
url: fileUrl,
progress$: new Observable<number>((observer) => {
blockBlobClient
.uploadData(file, {
onProgress: this.onProgress(observer),
})
.then(
this.onUploadComplete(observer, file, fileUrl),
this.onUploadError(observer, fileUrl)
);
}).pipe(distinctUntilChanged(), startWith(0), shareReplay()),
};
}
private onUploadError(observer: Subscriber<number>, fileUrl: string) {
return (error: any) => {
observer.error(error);
this.filesStateService.removeProgress(fileUrl);
};
}
private onUploadComplete(
observer: Subscriber<number>,
file: File,
fileUrl: string
) {
return () => {
observer.next(file.size);
this.filesStateService.removeProgress(fileUrl);
observer.complete();
};
}
private onProgress(observer: Subscriber<number>) {
return (progress: TransferProgressEvent) =>
observer.next(progress.loadedBytes);
}
在视图中,进度呈现如下:
<app-file-upload-progress
*ngIf="file.attachment.url | fileProgress | async as progress"
[progress]="progress"
[size]="file.attachment?.size"
></app-file-upload-progress>
file-progress.pipe只是从列表中返回进度:
@Pipe({
name: 'fileProgress',
})
export class FileProgressPipe implements PipeTransform {
constructor(private filesStateService: FilesStateService) {}
transform(value: string): Observable<number> {
if (!value) {
return null;
}
return this.filesStateService.getProgress(value);
}
}
以及存储文件进度的files-state.service :
@Injectable()
export class FilesStateService {
filesProgress: Map<string, Observable<number>> = new Map();
addProgress(url: string, progress$: Observable<number>): void {
this.filesProgress.set(url, progress$);
}
removeProgress(url: string): void {
this.filesProgress.delete(url);
}
getProgress(url: string): Observable<number> {
return this.filesProgress.get(url);
}
}
我不明白为什么,在文件成功上传并从filesProgress
列表中删除进度后,app-file-upload-progress没有从界面中删除。
我还尝试pure: false
在file-progress.pipe中使用,并且在上传完成后,如果我单击另一个元素,则会反映更改并从 UI 中删除进度(但从我读过的内容来看,使用pure: false
将导致表现不佳。
解决方案
您需要使用ChangeDetectorRef
服务。
当代码的某些区域(角度)无法使用默认检测检测更改时,ChangeDetector 是必需的。好消息是,在您的代码中使用 ChangeDetector 只需一行代码。您所要做的就是在更改之后this.detector.detectChanges();
这还需要您之前在构造函数中声明了服务。
constructor(private detector: ChangeDetectorRef)
演示:
constructor(private detector: ChangeDetectorRef) {
}
someMethod(){
setInterval(() => {
this.detector.detectChanges();
}, 5000);
}
推荐阅读
- loops - 批处理文件跳过 FOR LOOP
- cordova - 用于向 iOS SDK 发送面包屑信息的 Cordova 插件
- wordpress - 没有收到从我的服务器以表单形式发送的电子邮件 - wordpress 网站
- php - 如果我退出管理员帐户,Wordpress 菜单栏不显示
- regex - 如何改进基于正则表达式的单元格替换以每行操作而不是需要遍历每个单元格?
- asp.net - 使用 SQL Server 身份验证对 ASP.NET Web API 进行身份验证
- ruby-on-rails - 使用 Rails 验证,如何将短语列入白名单,例如“Learn Ruby”
- python - “NoneType”对象没有属性“月”
- java - 消息驱动 bean 不接收来自主题的消息
- visual-studio - 将网站发布到 Google Cloud VM 会出现多种类型的错误