Angular 8 组件中数据访问的奇怪之处

Mem*_*mmo 6 typescript angular angular8

我正在开发一个处理 xml 文件并返回接口数据结构的服务。
起初我以为服务已经正确返回了所有数据,但后来我意识到一些不清楚的事情,特别是当我要读取组件中的数据结构时。
这是我的服务:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { AppConfig } from 'src/app/app.config';
import { forkJoin, Subscription } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class BibliographyParserService {

  private editionUrls = AppConfig.evtSettings.files.editionUrls || [];
  private bibliographicCitations: Array<BibliographicCitation> = [];
  private subscriptions: Array<Subscription> = [];

  constructor(
    private http: HttpClient,
  ) {
  }

  private getHttpCallsOBSStream() {
    return this.editionUrls.map((path) =>  this.http.get(path, { responseType: 'text'}));
  }

  public getBibliographicCitations(): Array<BibliographicCitation> {
    const parser = new DOMParser();
    this.subscriptions.push(forkJoin(this.getHttpCallsOBSStream()).subscribe((responses) => {
      responses.forEach(response => {
        Array.from(parser.parseFromString(response, 'text/xml').getElementsByTagName('bibl')).forEach(citation => {
          if (citation.getElementsByTagName('author').length === 0 &&
              citation.getElementsByTagName('title').length === 0 &&
              citation.getElementsByTagName('date').length === 0) {
            const interfacedCitation: BibliographicCitation = {
              title: citation.textContent.replace(/\s+/g, ' '),
            };
            if (!this.bibliographicCitations.includes(interfacedCitation)) { this.bibliographicCitations.push(interfacedCitation); }
          } else {
            const interfacedCitation: BibliographicCitation = {
              authors: citation.getElementsByTagName('author'),
              title: String(citation.getElementsByTagName('title')[0]).replace(/\s+/g, ' '),
              date: citation.getElementsByTagName('date')[0],
            };
            if (!this.bibliographicCitations.includes(interfacedCitation)) { this.bibliographicCitations.push(interfacedCitation); }
          }
        });
      });
    }));
    return this.bibliographicCitations;
  }
}

export interface BibliographicCitation {
  authors?: HTMLCollectionOf<Element>;
  title: string;
  date?: Element;
}
Run Code Online (Sandbox Code Playgroud)

这是我的组件:

import { Component, AfterViewInit } from '@angular/core';
import { BibliographyParserService } from 'src/app/services/xml-parsers/bibliography-parser.service';

@Component({
  selector: 'evt-bibliography',
  templateUrl: './bibliography.component.html',
  styleUrls: ['./bibliography.component.scss']
})
export class BibliographyComponent implements AfterViewInit{

  constructor(
    public bps: BibliographyParserService,
  ) {
    console.log(this.bps.getBibliographicCitations());         // WORKS, return the correct data structure
    this.bps.getBibliographicCitations().forEach(console.log); // DOESN'T RETURN ANYTHING!
    console.log(this.bps.getBibliographicCitations().length);  // RETURN 0
  }

  ngAfterViewInit() {
    (document.querySelectorAll('.cloosingRood')[0] as HTMLElement).onclick = () => {
      (document.querySelectorAll('.biblSpace')[0] as HTMLElement).style.display = 'none';
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

非常奇怪的是这三个日志。我们可以看到他们之间的不同。
通过第一个日志,我可以在控制台中看到整个数据结构。
对于第二个,什么也没有发生。
对于第三个,长度等于0,这是不正确的,因为如第一个日志所示,数据结构已满......!
我不明白为什么会有这些奇怪的事情。我从 angular 文档中遗漏了什么吗?

PS:我不想在组件中进行订阅,否则我早就解决了......我想将逻辑与可视化分开并在服务中创建数据结构,就像我所做的那样。

Mem*_*mmo 1

您不必订阅该服务,但返回一个可观察的。
创建它的方式并不重要,重要的是尊重语法,这对于一个有角度的新手来说并不容易,可以理解!
根据blid给出的答案,我提出了这个解决方案,它可以调解反应式编程和命令式编程,而不会破坏您迄今为止所做的事情。显然,如果某人熟悉命令式编程来创建某些数据结构,他可以自由地做他喜欢做的事情,但如果您决定使用角度环境,您需要了解它提供的所有机会! 无论如何...这就是服务:


import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { AppConfig } from 'src/app/app.config';
import { forkJoin, Observable } from 'rxjs';
import { shareReplay, map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class BibliographyParserService {
  private editionUrls = AppConfig.evtSettings.files.editionUrls || [];
  private bibliographicCitations$: Observable<BibliographicCitation[]>;

  constructor(
    private http: HttpClient,
  ) {
    const parser = new DOMParser();
    const bibliographicCitations: Array<BibliographicCitation> = [];
    this.bibliographicCitations$ = forkJoin(this.getHttpCallsOBSStream()).pipe( //use pipe...
      map(responses => {                                                        //...and map
        responses.forEach(response => {
          Array.from(parser.parseFromString(response, 'text/xml').getElementsByTagName('bibl')).forEach(citation => {
            if (citation.getElementsByTagName('author').length === 0 &&
                citation.getElementsByTagName('title').length === 0 &&
                citation.getElementsByTagName('date').length === 0) {
              const interfacedCitation: BibliographicCitation = {
                title: citation.textContent.replace(/\s+/g, ' '),
              };
              if (!bibliographicCitations.includes(interfacedCitation)) { bibliographicCitations.push(interfacedCitation); }
            } else {
              const interfacedCitation: BibliographicCitation = {
                authors: citation.getElementsByTagName('author'),
                title: String(citation.getElementsByTagName('title')[0]).replace(/\s+/g, ' '),
                date: citation.getElementsByTagName('date')[0],
              };
              if (!bibliographicCitations.includes(interfacedCitation)) { bibliographicCitations.push(interfacedCitation); }
            }
          });
        });
        return bibliographicCitations; //This is the core!!!
        }),
      shareReplay(1)
    );
  }

  private getHttpCallsOBSStream() {
    return this.editionUrls.map((path) =>  this.http.get(path, { responseType: 'text'}));
  }

  public getBibliographicCitations(): Observable<Array<BibliographicCitation>> {
    return this.bibliographicCitations$;
  }
}

export interface BibliographicCitation {
  authors?: HTMLCollectionOf<Element>;
  title: string;
  date?: Element;
}

Run Code Online (Sandbox Code Playgroud)

这是您将在组件中执行的操作的示例:

constructor(
    public bps: BibliographyParserService,
  ) {
    this.bps.getBibliographicCitations().subscribe(response => {
        response.forEach(cit => {
            console.log(cit);
        });
    });
}
Run Code Online (Sandbox Code Playgroud)