异步管道无法填充数组中的新数据

时间:2019-07-08 20:27:32

标签: angular rxjs

我的应用程序需要发出许多api请求(大约500个)并显示数据。当请求完成时,它需要显示结果。到目前为止,我已将其设置为使用带有可观察对象的异步管道。

我尝试将ChangeDetectorRef.detectChanges()放入complete()函数调用中。但是视图并没有受到任何影响。

news.component.ts

export class NewsComponent implements OnInit {

  news: Observable<News[]>;
  temp: News[] = new Array();

  constructor(private dataService: DataService, private ref: ChangeDetectorRef) {
  }

  ngOnInit() {
    this.news = this.getData();
  }

  getData(): Observable<News[]> {
    let newsArr = new Subject<News[]>();
    this.dataService.getTopNews().subscribe(val => {
      this.temp.push(val);
      newsArr.next(this.temp);
    }, null, () => {
      newsArr.complete();
      this.ref.detectChanges();
      console.log(this.news); //print all fetched data
    });
    return newsArr.asObservable();
  }
}

news.component.html

<app-news-item *ngFor="let newsItem of news | async" [news]="newsItem">
</app-news-item>

news-item.component.ts

@Component({
  selector: 'app-news-item',
  templateUrl: './news-item.component.html',
  styleUrls: ['./news-item.component.css']
})
export class NewsItemComponent implements OnInit {
  @Input() news: Subject<News>;
  constructor() { }

  ngOnInit() {
  }

}

视图(html)仅更新一次,开始时仅更新一些数据。数据正在正确加载,并且在提取所有数据后也会触发complete()。

3 个答案:

答案 0 :(得分:2)

之所以不起作用,是因为您似乎将一个数组推入了临时数组,所以它实际上是一个数组数组...您可以像修复它一样简单

this.temp.push(...val)

不过,我可能会误解getTopNews实际发出的信息(数组或单个新闻项)

但是,我建议尝试使用某些运算符来正确执行此操作,尤其是累积数据的扫描运算符,因为我假设getTopNews发出多个“块”

import {scan} from 'rxjs/operators';

getData(): Observable<News[]> {
    return this.dataService.getTopNews().pipe(
      scan((acc, curr) => acc.concat(curr), []) // or acc.concat([curr]) if curr is actually a single news item and not an array
      // if you're not sure if its a single or array:
      // acc.concat(Array.isArray(curr) ? curr : [curr])
    );
  }
}

这是一个简单得多的结构,不需要temp变量或内部主题。如果您只希望它在全部完成后就呈现,那么只需将scan替换为reduce。

您的新闻项目组件中似乎也有一个错误,因为它似乎期望新闻主题而不是实际新闻,而这正是根据其余代码得到的。

答案 1 :(得分:0)

因为您的应用程序发出了将近500个请求,并且您在所有请求完成后呈现了数据,所以我建议采用更明确的方法,例如不使用异步管道。

export class NewsComponent implements OnInit, OnDestroy {
  private unsub: Subscription;
  news:News[] = [];

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.getData();
  }

  getData(): Observable<News[]> {
    const tmp: News[] = [];
    this.unsub = this.dataService.getTopNews().subscribe(val => {
      tmp.push(...val);
    }, null, () => {
      this.news = tmp;
      console.log(this.news); //print all fetched data
    });
  }

  ngOnDestroy() {
    this.unsub.unsubscribe();
  }
}

并在您的模板中

<app-news-item *ngFor="let newsItem of news" [news]="newsItem"></app-news-item>

答案 2 :(得分:0)

为什么事情太复杂了?只需将服务中的可观察对象放在组件上,然后使用异步管道进行订阅即可,它将负责订阅和取消订阅。

export class NewsComponent implements OnInit {

  news = this.dataService.getTopNews();

  constructor(private dataService: DataService) {
  }
}