Асинхронный канал не заполняет новые данные из массива - PullRequest
1 голос
/ 08 июля 2019

Мое приложение должно сделать несколько запросов 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 ]

2 голосов
/ 08 июля 2019

Причина, по которой это не работает, в том, что вы выдвигаете массив во временный массив, так что на самом деле это массив массивов ... вы можете исправить это так же просто, как

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 или внутреннем субъекте. Если вы хотите, чтобы он отображался только после того, как ВСЕ выполнено, просто замените сканирование на уменьшение.

Кажется также, что в вашем компоненте новостей есть ошибка, так как кажется, что он ожидает тему новости вместо реальной новости, то есть то, что он получает, основываясь на остальной части кода.

0 голосов
/ 09 июля 2019

Почему все усложняется?Просто поместите наблюдаемое из сервиса в компонент и используйте асинхронный канал, чтобы подписаться на него, он позаботится о подписке и отписке ..

export class NewsComponent implements OnInit {

  news = this.dataService.getTopNews();

  constructor(private dataService: DataService) {
  }
}
0 голосов
/ 08 июля 2019

, так как ваше приложение делает почти 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...