首页 > 解决方案 > 如何从不同的来源设置我的界面对象的值

问题描述

我有一个包含以下项目的 json 文件:

[
    {"id": 1, "fileName": "1.txt", "title": "First Kidney Transplant in the Region"},
    {"id": 2, "fileName": "2.txt", "title": "Another article"}
]

我有一个带有以下对象的接口 INewsArticle[]

export interface INewsArticles{
id : number, 
fileName : string,
title : string,
content : Text

}

除了内容之外的所有内容都是从我的 json 文件中加载的。我想要做的是使用一个订阅从 .txt 文件中获取每篇文章的相应内容,我不知道如何在打字稿中做到这一点。

这是我的订阅代码:this.svcNewsArticles.LoadArticles().subscribe(data => this._newsArticles = data);

这是我的服务:

    private _srcArticles : string = "./assets/news-articles/newsList.json";
  constructor(private http:HttpClient) { }

  LoadArticles() : Observable<INewsArticles[]>{
    return this.http.get<INewsArticles[]>(this._srcArticles);
  }

我目前拥有的是获取我的 INewsArticles[],使用 *ngFor 将其绑定到 HTML,然后调用另一个方法来订阅另一个请求,以使用 INewsArticles[].fileName 的参数从我的内容目录加载内容。但这在控制台上测试时会导致无限循环。

这是我的 HTML:

    <div id="divContainer" class="container" fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutAlign="center" fxLayoutGap="20px" [style.marginTop.%]="_marginTop">
    <div id="divHeader" [fxHide]="_hideHeader">
        <h1>What's New?</h1>
    </div>
    
    <mat-card fxFlex.gt-sm="30%" fxFlex.lt-md="95%" *ngFor = "let article of _newsArticles">
        <mat-card-header>
            <mat-card-title> 
                {{ article.title }}
            </mat-card-title>
        </mat-card-header> 
        
        <mat-card-content class="scrollable">  
            {{ getContent(article.fileName) }}
            <!-- <embed src='../../../../assets/news-articles/content/{{ article.fileName }}'> -->
            <!-- {{ getContent() }} -->
        </mat-card-content>
    </mat-card> 
</div>

这是我的订阅:

    getContent(fileName : string){
    this.svcNewsArticles.GetContent(fileName).subscribe(data => {console.log(data)}, err => {console.log(err)});
  }

这是我的服务:

    GetContent(fileName : String){
    return this.http.get('./assets/news-articles/content/'+fileName, {responseType : 'text'}); 
  }

我是新手,请与我裸露。

标签: angulartypescriptrxjshttprequesttext-files

解决方案


您可以使用任何高阶映射运算符(例如 switchMap 或 mergeMap)同时执行这两个 HTML 请求。

像这样的东西:

  posts$ = this.http.get<Post[]>(this.postUrl).pipe(
    mergeMap(posts =>
      forkJoin(
        posts.map(post =>
          this.http.get<User>(`${this.userUrl}/${post.userId}`).pipe(
            map(user => ({
              title: post.title,
              userName: user.name
            }))
          )
        )
      )
    )
  );

你可以在这里找到一个有效的 Stackblitz:https ://stackblitz.com/edit/angular-simple-posts-user-mergemap-deborahk

将其应用于您的代码,它看起来像这样:

  this.http.get<INewsArticles[]>(this._srcArticles).pipe(
    mergeMap(articles=>
      forkJoin(
        articles.map(article=>
          this.http.get('./assets/news-articles/content/'+article.fileName, {responseType : 'text'}).pipe(
            map(content=> ({
                id : article.id, 
                fileName : article.fileName,
                title : article.title,
                content : content
            }))
          )
        )
      )
    )
  );

注意:这尚未经过语法检查或验证。请提供一个小的工作 StackBlitz 示例以获得更具体和语法检查的答案。

此代码首先获取所有文章。然后它使用 mergeMap 来处理文章并自动订阅内部的 Observables。forkJoin 允许我们使用articles.map 处理文章数组中的每篇文章。

然后我们对文章内容发出 http 请求,并将检索到的数据映射到所需的接口中。

结果是包含内容的 Observable<INewsArticles[]>。然后,您可以在模板中进行简单的插值绑定。

更新:您可以使用对象解构稍微缩短语法:

  this.http.get<INewsArticles[]>(this._srcArticles).pipe(
    mergeMap(articles=>
      forkJoin(
        articles.map(article=>
          this.http.get('./assets/news-articles/content/'+article.fileName, {responseType : 'text'}).pipe(
            map(content=> ({
                ...article, 
                content : content
            }))
          )
        )
      )
    )
  );

...article语法复制所有文章属性。然后你只需要添加content.


推荐阅读