Angular Http Client отправка многим запросам - PullRequest
0 голосов
/ 23 января 2019

Привет всем, я пытаюсь выставить простой запрос POST через HttpClient из '@ angular / common / http';

Итак, я получил метод, который выглядит следующим образом

getRecommendations(answers: any, vehicles:  Array<string>) {
// map answers to API interface
const apiAnswers = answers.map( answer => {
  return {
    questionId: answer.questionId,
    answer: parseInt(answer.answerKey, 10)
  };
});
const result = {};
result['vehicles'] = vehicles;
result['answers'] = apiAnswers;

return this.http.post(environment.api + '/recommend/', result
).pipe(
  map( (res: any) => {
    return res.Packages;
  }),
  catchError( (err) => {
    this.errorService.showError('Get Recommendation Error');
    return of(`Get Recommendation Error: ${err}`);
  }),
  finalize( () => {
    // hide loader no matter what happens
    this.appLoaderService.setLoading(false);
  })
);
}

Я ожидаю, что эта функция отправит запрос по почте и вернет ответ, но вместо этого ist делает 6 запросов ....

Я на 100% уверен, что этот метод вызывается только один раз, поэтому я предполагаю проблему, лежит где-то внутри метода this.http.post, но я не могу понять, в чем проблема, кто-нибудь может мне помочь?

Редактировать: так подписывается метод

    export class RecommendationsComponent implements AfterViewInit {

  @ViewChildren('packageComponent', { read: ElementRef }) packageElements: QueryList<ElementRef>;

  public translations$: Observable<IResultTranslations>;
  public packages$: Observable<IPackage[]>;
  public recommendedPackages$: Observable<IPackage[]>;
  public optionalPackages$: Observable<IPackage[]>;
  public nonPreferredPackages$: Observable<IPackage[]>;
  public vehicles$: Observable<IVehicle[]>;
  public selectedVehicles: IVehicle[];
  public height: number;

  public selectedPackages: IPackage[] = [];

  constructor(private translate: TranslateService,
    private apiService: ApiService,
    private recommendationService: RecommendationService,
    private router: Router,
    private uiService: UiService,
    private cd: ChangeDetectorRef,
    private translateService: TranslateService,
    private hostService: HostService
  ) {
    const answers = this.recommendationService.getAnswers();
    const vehicles = this.recommendationService.getVehicles();

    // navigate to start if no answers available
    if (!answers || answers.length === 0) {
      this.router.navigate(['']);
      return;
    }

    this.packages$ = this.apiService.getRecommendations(answers, vehicles);
    this.translations$ = this.apiService.getTranslations(answers, vehicles);



    // select recommended packages
    this.packages$ = this.packages$.pipe(
      map( packages => packages.map( p => {
        if (p.recommended) {
          this.toggleSelectedPackage(p, true);
          p.selected = true;
        }
        return p;
      }))
    );

    // filter all recommended packages
    this.recommendedPackages$ = this.packages$.pipe(
      map( packages => packages.filter( p => p.recommended && !p.nonPreferred))
    );

    // filter all optional packages
    this.optionalPackages$ = this.packages$.pipe(
      map( packages => packages.filter( p => !p.recommended && !p.nonPreferred))
    );

    // filter all non preferred packages
    this.nonPreferredPackages$ = this.packages$.pipe(
      map( packages => packages.filter( p => p.nonPreferred))
    );

    // init selectedVehicles
    this.selectedVehicles = [];
    // get vehicles from localized content
    this.vehicles$ = this.translateService.get('vehicles').pipe(
      // filter vehicles with ids from vehicle component
      map(vehiclesArray => vehiclesArray.filter(vehicle => vehicles.indexOf(vehicle.Id) > -1)),
      // add selected flag and toggle function to vehicles
      map(vehiclesArray => vehiclesArray.map(vehicle => {
        vehicle.selected = false;
        vehicle.toggleSelected = () => {
          const selected = (vehiclesArray.filter(selectedVehicle => selectedVehicle.selected === true)).length;
          // don't toggle if it is the last active vehicle
          if ( !vehicle.selected || selected > 1) {
            vehicle.selected = !vehicle.selected;
            this.selectedVehicles = vehiclesArray.filter(selectedVehicle => selectedVehicle.selected);
          }
          return vehicle.selected;
        };
        vehicle.toggleSelected();
        return vehicle;
      }))
    );
  }
  ngAfterViewInit() {

    // synchronize height of package cards after all packages got rendered
    this.packageElements.changes.pipe(
      withLatestFrom(this.packages$),
      map(([change, packages]) => {
        if (packages.length === this.packageElements.toArray().length) {
          return this.uiService.getHeightOfHighestElement(this.packageElements.toArray());
        }
      })
    ).subscribe( (height) => {
        this.height = height;
        this.cd.detectChanges();
    });
  }
}

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Для дальнейшего использования, это проблема, описанная здесь Угловая-ловушка-множественные-HTTP-запросы, с-rxjs-и-наблюдаемые Асинхры /

Каждый асинхронный канал запускает новый HTTP-запрос, потому что каждый результат $ | async создает новую подписку / поток для результата $ Observable.

Это не ошибка, а характер реализации Observables для обеспечения гибкости.

Вы можете представить наблюдаемый результат $ как объявление функции, и каждый результат $ | async вызывает ту же функцию.

0 голосов
/ 23 января 2019

http-вызов не выполняется, пока что-то на него не подпишется.Поэтому какой-то другой метод должен вызывать getRecommendations несколько раз.

Метод запускается один раз, и вы возвращаете еще не подписанный HTTP-вызов.Поэтому, когда вы подписываетесь на this.packages$ впоследствии, getRecommendations больше не запускается, потому что он уже вернулся.

...