Angular делает http звонок дважды - PullRequest
1 голос
/ 24 апреля 2020

Я разрабатываю приложение Angular. У меня есть собственный источник данных, который получает данные с сервера и заполняет таблицу материалов.

Вот метод из службы:

dataChange: BehaviorSubject<Segment[]> = new BehaviorSubject<Segment[]>([]);

 getSegmentsByProgramId(programId: number) {
    this.subscription = this.httpClient
      .get<Segment[]>(`${environment.baseUrl}/segment/program/${programId}`)

      .subscribe(
        segments => {
          this.dataChange.next(segments);
        },
        (error: HttpErrorResponse) => {
          console.log(error.message);
        },
        () => console.log('completed')
      );
  }

Вот шаблон родительского компонента:

<mat-card class="mat-elevation-z10 mt-2">
  <mat-card-header>
    <mat-card-title>
      <h4 class="card-title">Segments</h4>
    </mat-card-title>
  </mat-card-header>
  <mat-card-content class="mr-3">
    <mat-tab-group>
      <mat-tab *ngFor="let program of programs$ | async">
        <ng-template mat-tab-label>
          <span> {{ program.name }} </span></ng-template
        >
        <app-segment-table [programId]="program.id"></app-segment-table>
      </mat-tab>
    </mat-tab-group>
  </mat-card-content>
</mat-card>

Вот .ts родительского компонента:

export class SegmentListComponent implements OnInit {
  programs$: Observable<Program[]>;
  members$: Observable<number>;

  @Output() createSegmentEvent = new EventEmitter();

  constructor(private programService: ProgramService, private membersService: MembersService) {}

  ngOnInit() {
    this.programs$ = this.programService.programs$;
    this.members$ = this.membersService.members$.pipe(map(members => members.length));
  }

  createSegment() {
    this.createSegmentEvent.next(true);
  }
}

В дочернем ts:

export class SegmentTableComponent implements OnInit {
  segmentsDatabase: SegmentsService | null;
  dataSource: SegmentsDataSource | null;
  displayedColumns = ['name', 'startDate', 'endDate', 'cashback', 'strategy', 'status', 'members', 'actions'];
  index: number;
  id: number;

  isLoading = true;

  @Input() programId: number | any;

  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
  @ViewChild(MatSort, { static: true }) sort: MatSort;
  @ViewChild('filter', { static: true }) filter: ElementRef;

  constructor(public httpClient: HttpClient, private segmentsService: SegmentsService, public dialog: MatDialog) {}

  ngOnInit() {
    this.loadData(this.programId);
  }

  public loadData(programId: number | any) {
    this.segmentsDatabase = new SegmentsService(this.httpClient);
    this.dataSource = new SegmentsDataSource(this.segmentsDatabase, this.paginator, this.sort, programId);

    fromEvent(this.filter.nativeElement, 'keyup')
      .pipe(debounceTime(150), distinctUntilChanged())
      .subscribe(() => {
        if (!this.dataSource) {
          return;
        }
        this.dataSource.filter = this.filter.nativeElement.value;
      });
  }
}

А вот dataSuorce:

export class SegmentsDataSource extends DataSource<Segment> {
  _filterChange = new BehaviorSubject('');

  get filter(): string {
    return this._filterChange.value;
  }

  set filter(filter: string) {
    this._filterChange.next(filter);
  }

  filteredData: Segment[] = [];
  renderedData: Segment[] = [];

  constructor(
    public _segmentsDataBase: SegmentsService,
    public _paginator: MatPaginator,
    public _sort: MatSort,
    public _programId: number | any
  ) {
    super();
    this._filterChange.subscribe(() => (this._paginator.pageIndex = 0));
  }

  connect(): Observable<Segment[]> {
    const displayDataChanges = [
      this._segmentsDataBase.dataChange,
      this._sort.sortChange,
      this._filterChange,
      this._paginator.page,
      this._programId
    ];

    this._segmentsDataBase.getSegmentsByProgramId(this._programId);

    return merge(...displayDataChanges).pipe(
      map(() => {
        this.filteredData = this._segmentsDataBase.data.slice().filter((segment: Segment) => {
          const searchStr = (
            segment.name +
            segment.startDate +
            segment.endDate +
            segment.cashback +
            segment.status
          ).toLowerCase();
          return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
        });
        const sortedData = this.sortData(this.filteredData.slice());

        const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
        this.renderedData = sortedData.splice(startIndex, this._paginator.pageSize);
        return this.renderedData;
      })
    );
  }

  disconnect() {}
}

Когда я нахожусь на этой странице и перезагружаю ее - все работает отлично. Сервис вызывается один раз. Но когда я перехожу с другой страницы ... мой сервер вызывается дважды.

Понятия не имею, что вызывает эту проблему ... Может быть, кто-то может помочь мне решить ее.

1 Ответ

1 голос
/ 24 апреля 2020

лучше работать с pipe в запросе this.httpClient для получения асинхронного результата. Evtl. вы работаете в ситуации ошибки при переносе на другой сайт, и параметр повтора angular будет повторять запрос.

, например:

getHero(id: number): Observable<Hero> {
  const url = `${this.heroesUrl}/${id}`;
  return this.http.get<Hero>(url).pipe(
    tap(_ => this.log(`fetched hero id=${id}`)),
    catchError(this.handleError<Hero>(`getHero id=${id}`))
  );
}

Вот исх

...