使用带有 RxJS 主题的服务在 Angular 组件之间传递数据

问题描述 投票:0回答:1

我正在尝试做什么

我的 Angular 客户端应用程序中有两个不相关的组件。第一个组件负责从服务器获取和处理数据。我正在尝试使用订阅回调函数导航到新页面并显示已处理的数据(blob)。更具体地说,我想转到一个新选项卡并使用不相关的组件预览 Word 文档。我发现可以使用具有 RxJS 主题的服务通过不相关的组件传递数据。

我得到了什么

我已经实现了一些代码,但我的博客没有到达预览组件。

我尝试过的

这是我想出的一些代码:

传输 Blob 对象的服务

@Injectable()
export class DocPreviewService {
  private blob = new BehaviorSubject<Blob | undefined>(undefined);
  public share$ = this.blob.asObservable();

  constructor() {}

  setBlob(blob: Blob) {
    this.blob.next(blob);
  }
}

负责从服务器检索 blob 的函数(第一个组件)

  showReport(selected_id: string) {
    const url = this.router.serializeUrl(this.router.createUrlTree([`tools/${selected_id}/preview`]));
    // it's important that the page opens in a new tab
    window.open(url, '_blank');

    this.report_service.createReport(this.calc_items[selected_id]).subscribe({
      next: (doc_blob: Blob) => {
        {          
          this.doc_preview_service.setBlob(doc_blob);
        }
      },
      error: (error: any) => {
      },
    })
  }

负责查看文档的组件(第二个组件)

export class DocPreviewComponent implements OnChanges, AfterViewInit, OnDestroy {
  doc_blob?: Blob;
  @ViewChild('doc_preview') doc_preview!: ElementRef;
  subscription: Subscription;
  
  constructor(private doc_preview_service: DocPreviewService, private local_storage: LocalStorageService) {
    this.subscription = this.doc_preview_service.share$.subscribe(blob => {
      this.doc_blob = blob;
    });
  }

  ngOnChanges(changes: SimpleChanges): void {}

  ngAfterViewInit(): void {
    if (this.doc_blob) {
      doc.renderAsync(this.doc_blob, this.doc_preview.nativeElement)
      .then(x => console.log("docx: finished"));
    }
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}

任何帮助将不胜感激。谢谢你。

angular typescript rxjs rxjs-observables behaviorsubject
1个回答
1
投票

实际上,主题发射器方法有一个限制,它仅适用于单个选项卡中不相关组件之间的通信,不可能进行跨选项卡通信,因为该服务在每个选项卡中将有两个单独的实例,因此永远不会收到事件

要解决这种情况,您只需将 API 调用参数附加到 URL 即可

打开选项卡的代码

  showReport(selected_id: string) {
    // basically we append the required param needed for making the API 
    // call, then we use it to call the blob logic on the other tab initialization!
    const url = this.router.serializeUrl(this.router.createUrlTree([`tools/${selected_id}/preview?id=${this.calc_items[selected_id]}`]));
    // it's important that the page opens in a new tab
    window.open(url, '_blank');
  }

打开 blob 的组件将是

export class DocPreviewComponent implements OnChanges, AfterViewInit, OnDestroy {
  doc_blob?: Blob;
  @ViewChild('doc_preview') doc_preview!: ElementRef;
  subscription: Subscription;
  
  constructor(private doc_preview_service: DocPreviewService, private local_storage: LocalStorageService) { }

  ngOnChanges(changes: SimpleChanges): void {}

  ngAfterViewInit(): void {
      this.report_service.createReport(this.activatedRoute.snapshot.queryParams.id).subscribe({
         next: (doc_blob: Blob) => {
              this.doc_blob = doc_blob;
              if (this.doc_blob) {
                  doc.renderAsync(this.doc_blob, this.doc_preview.nativeElement)
                  .then(x => console.log("docx: finished"));
              }
         },
         error: (error: any) => {},
     })
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.